/* * bnx2i_iscsi.c: QLogic NetXtreme II iSCSI driver. * * Copyright (c) 2006 - 2013 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * Copyright (c) 2014, QLogic Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * Written by: Anil Veerabhadrappa ([email protected]) * Previously Maintained by: Eddie Wai ([email protected]) * Maintained by: [email protected] */ #include <linux/slab.h> #include <scsi/scsi_tcq.h> #include <scsi/libiscsi.h> #include "bnx2i.h" struct scsi_transport_template *bnx2i_scsi_xport_template; struct iscsi_transport bnx2i_iscsi_transport; static const struct scsi_host_template bnx2i_host_template; /* * Global endpoint resource info */ static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); static int bnx2i_adapter_ready(struct bnx2i_hba *hba) { … } /** * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks * @cmd: iscsi cmd struct pointer * @buf_off: absolute buffer offset * @start_bd_off: u32 pointer to return the offset within the BD * indicated by 'start_bd_idx' on which 'buf_off' falls * @start_bd_idx: index of the BD on which 'buf_off' falls * * identifies & marks various bd info for scsi command's imm data, * unsolicited data and the first solicited data seq. */ static void bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off, u32 *start_bd_off, u32 *start_bd_idx) { … } /** * bnx2i_setup_write_cmd_bd_info - sets up BD various information * @task: transport layer's cmd struct pointer * * identifies & marks various bd info for scsi command's immediate data, * unsolicited data and first solicited data seq which includes BD start * index & BD buf off. his function takes into account iscsi parameter such * as immediate data and unsolicited data is support on this connection. */ static void bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task) { … } /** * bnx2i_map_scsi_sg - maps IO buffer and prepares the BD table * @hba: adapter instance * @cmd: iscsi cmd struct pointer * * map SG list */ static int bnx2i_map_scsi_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) { … } /** * bnx2i_iscsi_map_sg_list - maps SG list * @cmd: iscsi cmd struct pointer * * creates BD list table for the command */ static void bnx2i_iscsi_map_sg_list(struct bnx2i_cmd *cmd) { … } /** * bnx2i_iscsi_unmap_sg_list - unmaps SG list * @cmd: iscsi cmd struct pointer * * unmap IO buffers and invalidate the BD table */ void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd) { … } static void bnx2i_setup_cmd_wqe_template(struct bnx2i_cmd *cmd) { … } /** * bnx2i_bind_conn_to_iscsi_cid - bind conn structure to 'iscsi_cid' * @hba: pointer to adapter instance * @bnx2i_conn: pointer to iscsi connection * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1) * * update iscsi cid table entry with connection pointer. This enables * driver to quickly get hold of connection structure pointer in * completion/interrupt thread using iscsi context ID */ static int bnx2i_bind_conn_to_iscsi_cid(struct bnx2i_hba *hba, struct bnx2i_conn *bnx2i_conn, u32 iscsi_cid) { … } /** * bnx2i_get_conn_from_id - maps an iscsi cid to corresponding conn ptr * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1) */ struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, u16 iscsi_cid) { … } /** * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool * @hba: pointer to adapter instance */ static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba) { … } /** * bnx2i_free_iscsi_cid - returns tcp port to free list * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID to free */ static void bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid) { … } /** * bnx2i_setup_free_cid_que - sets up free iscsi cid queue * @hba: pointer to adapter instance * * allocates memory for iscsi cid queue & 'cid - conn ptr' mapping table, * and initialize table attributes */ static int bnx2i_setup_free_cid_que(struct bnx2i_hba *hba) { … } /** * bnx2i_release_free_cid_que - releases 'iscsi_cid' queue resources * @hba: pointer to adapter instance */ static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba) { … } /** * bnx2i_alloc_ep - allocates ep structure from global pool * @hba: pointer to adapter instance * * routine allocates a free endpoint structure from global pool and * a tcp port to be used for this connection. Global resource lock, * 'bnx2i_resc_lock' is held while accessing shared global data structures */ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba) { … } /** * bnx2i_free_ep - free endpoint * @ep: pointer to iscsi endpoint structure */ static void bnx2i_free_ep(struct iscsi_endpoint *ep) { … } /** * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command * @hba: adapter instance pointer * @session: iscsi session pointer * @cmd: iscsi command structure */ static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session, struct bnx2i_cmd *cmd) { … } /** * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table * @hba: adapter instance pointer * @session: iscsi session pointer */ static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba, struct iscsi_session *session) { … } /** * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session * @hba: adapter instance pointer * @session: iscsi session pointer */ static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba, struct iscsi_session *session) { … } /** * bnx2i_setup_mp_bdt - allocate BD table resources * @hba: pointer to adapter structure * * Allocate memory for dummy buffer and associated BD * table to be used by middle path (MP) requests */ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba) { … } /** * bnx2i_free_mp_bdt - releases ITT back to free pool * @hba: pointer to adapter instance * * free MP dummy buffer and associated BD table */ static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba) { … } /** * bnx2i_drop_session - notifies iscsid of connection error. * @cls_session: iscsi cls session pointer * * This notifies iscsid that there is a error, so it can initiate * recovery. * * This relies on caller using the iscsi class iterator so the object * is refcounted and does not disapper from under us. */ void bnx2i_drop_session(struct iscsi_cls_session *cls_session) { … } /** * bnx2i_ep_destroy_list_add - add an entry to EP destroy list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * EP destroy queue manager */ static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_ep_destroy_list_del - add an entry to EP destroy list * * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * EP destroy queue manager */ static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * pending conn offload completion queue manager */ static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * pending conn offload completion queue manager */ static int bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints * * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID to find * */ struct bnx2i_endpoint * bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid) { … } /** * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID to find * */ struct bnx2i_endpoint * bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid) { … } /** * bnx2i_ep_active_list_add - add an entry to ep active list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * current active conn queue manager */ static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_ep_active_list_del - deletes an entry to ep active list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * current active conn queue manager */ static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_setup_host_queue_size - assigns shost->can_queue param * @hba: pointer to adapter instance * @shost: scsi host pointer * * Initializes 'can_queue' parameter based on how many outstanding commands * the device can handle. Each device 5708/5709/57710 has different * capabilities */ static void bnx2i_setup_host_queue_size(struct bnx2i_hba *hba, struct Scsi_Host *shost) { … } /** * bnx2i_alloc_hba - allocate and init adapter instance * @cnic: cnic device pointer * * allocate & initialize adapter structure and call other * support routines to do per adapter initialization */ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) { … } /** * bnx2i_free_hba- releases hba structure and resources held by the adapter * @hba: pointer to adapter instance * * free adapter structure and call various cleanup routines. */ void bnx2i_free_hba(struct bnx2i_hba *hba) { … } /** * bnx2i_conn_free_login_resources - free DMA resources used for login process * @hba: pointer to adapter instance * @bnx2i_conn: iscsi connection pointer * * Login related resources, mostly BDT & payload DMA memory is freed */ static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba, struct bnx2i_conn *bnx2i_conn) { … } /** * bnx2i_conn_alloc_login_resources - alloc DMA resources for login/nop. * @hba: pointer to adapter instance * @bnx2i_conn: iscsi connection pointer * * Mgmt task DNA resources are allocated in this routine. */ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba, struct bnx2i_conn *bnx2i_conn) { … } /** * bnx2i_iscsi_prep_generic_pdu_bd - prepares BD table. * @bnx2i_conn: iscsi connection pointer * * Allocates buffers and BD tables before shipping requests to cnic * for PDUs prepared by 'iscsid' daemon */ static void bnx2i_iscsi_prep_generic_pdu_bd(struct bnx2i_conn *bnx2i_conn) { … } /** * bnx2i_iscsi_send_generic_request - called to send mgmt tasks. * @task: transport layer task pointer * * called to transmit PDUs prepared by the 'iscsid' daemon. iSCSI login, * Nop-out and Logout requests flow through this path. */ static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task) { … } /********************************************************************** * SCSI-ML Interface **********************************************************************/ /** * bnx2i_cpy_scsi_cdb - copies LUN & CDB fields in required format to sq wqe * @sc: SCSI-ML command pointer * @cmd: iscsi cmd pointer */ static void bnx2i_cpy_scsi_cdb(struct scsi_cmnd *sc, struct bnx2i_cmd *cmd) { … } static void bnx2i_cleanup_task(struct iscsi_task *task) { … } /** * bnx2i_mtask_xmit - transmit mtask to chip for further processing * @conn: transport layer conn structure pointer * @task: transport layer command structure pointer */ static int bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) { … } /** * bnx2i_task_xmit - transmit iscsi command to chip for further processing * @task: transport layer command structure pointer * * maps SG buffers and send request to chip/firmware in the form of SQ WQE */ static int bnx2i_task_xmit(struct iscsi_task *task) { … } /** * bnx2i_session_create - create a new iscsi session * @ep: pointer to iscsi endpoint * @cmds_max: user specified maximum commands * @qdepth: scsi queue depth to support * @initial_cmdsn: initial iscsi CMDSN to be used for this session * * Creates a new iSCSI session instance on given device. */ static struct iscsi_cls_session * bnx2i_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, uint32_t initial_cmdsn) { … } /** * bnx2i_session_destroy - destroys iscsi session * @cls_session: pointer to iscsi cls session * * Destroys previously created iSCSI session instance and releases * all resources held by it */ static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session) { … } /** * bnx2i_conn_create - create iscsi connection instance * @cls_session: pointer to iscsi cls session * @cid: iscsi cid as per rfc (not NX2's CID terminology) * * Creates a new iSCSI connection instance for a given session */ static struct iscsi_cls_conn * bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) { … } /** * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together * @cls_session: pointer to iscsi cls session * @cls_conn: pointer to iscsi cls conn * @transport_fd: 64-bit EP handle * @is_leading: leading connection on this session? * * Binds together iSCSI session instance, iSCSI connection instance * and the TCP connection. This routine returns error code if * TCP connection does not belong on the device iSCSI sess/conn * is bound */ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_fd, int is_leading) { … } /** * bnx2i_conn_destroy - destroy iscsi connection instance & release resources * @cls_conn: pointer to iscsi cls conn * * Destroy an iSCSI connection instance and release memory resources held by * this connection */ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn) { … } /** * bnx2i_ep_get_param - return iscsi ep parameter to caller * @ep: pointer to iscsi endpoint * @param: parameter type identifier * @buf: buffer pointer * * returns iSCSI ep parameters */ static int bnx2i_ep_get_param(struct iscsi_endpoint *ep, enum iscsi_param param, char *buf) { … } /** * bnx2i_host_get_param - returns host (adapter) related parameters * @shost: scsi host pointer * @param: parameter type identifier * @buf: buffer pointer */ static int bnx2i_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { … } /** * bnx2i_conn_start - completes iscsi connection migration to FFP * @cls_conn: pointer to iscsi cls conn * * last call in FFP migration to handover iscsi conn to the driver */ static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn) { … } /** * bnx2i_conn_get_stats - returns iSCSI stats * @cls_conn: pointer to iscsi cls conn * @stats: pointer to iscsi statistic struct */ static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) { … } /** * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices * @dst_addr: target IP address * * check if route resolves to BNX2 device */ static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr) { … } /** * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources * @hba: pointer to adapter instance * @ep: endpoint (transport identifier) structure * * destroys cm_sock structure and on chip iscsi context */ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_ep_connect - establish TCP connection to target portal * @shost: scsi host * @dst_addr: target IP address * @non_blocking: blocking or non-blocking call * * this routine initiates the TCP/IP connection by invoking Option-2 i/f * with l5_core and the CNIC. This is a multi-step process of resolving * route to target, create a iscsi connection context, handshaking with * CNIC module to create/initialize the socket struct and finally * sending down option-2 request to complete TCP 3-way handshake */ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, int non_blocking) { … } /** * bnx2i_ep_poll - polls for TCP connection establishement * @ep: TCP connection (endpoint) handle * @timeout_ms: timeout value in milli secs * * polls for TCP connect request to complete */ static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) { … } /** * bnx2i_ep_tcp_conn_active - check EP state transition * @bnx2i_ep: endpoint pointer * * check if underlying TCP connection is active */ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) { … } /** * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw * @bnx2i_ep: TCP connection (bnx2i endpoint) handle * * executes TCP connection teardown process */ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) { … } /** * bnx2i_ep_disconnect - executes TCP connection teardown process * @ep: TCP connection (iscsi endpoint) handle * * executes TCP connection teardown process */ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) { … } /** * bnx2i_nl_set_path - ISCSI_UEVENT_PATH_UPDATE user message handler * @shost: scsi host pointer * @params: pointer to buffer containing iscsi path message */ static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params) { … } static umode_t bnx2i_attr_is_visible(int param_type, int param) { … } /* * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template * used while registering with the scsi host and iSCSI transport module. */ static const struct scsi_host_template bnx2i_host_template = …; struct iscsi_transport bnx2i_iscsi_transport = …;