/* bnx2i_hwi.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/gfp.h> #include <scsi/scsi_tcq.h> #include <scsi/libiscsi.h> #include "bnx2i.h" DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); /** * bnx2i_get_cid_num - get cid from ep * @ep: endpoint pointer * * Only applicable to 57710 family of devices */ static u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep) { … } /** * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type * @hba: Adapter for which adjustments is to be made * * Only applicable to 57710 family of devices */ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba) { … } /** * bnx2i_get_link_state - get network interface link state * @hba: adapter instance pointer * * updates adapter structure flag based on netdev state */ static void bnx2i_get_link_state(struct bnx2i_hba *hba) { … } /** * bnx2i_iscsi_license_error - displays iscsi license related error message * @hba: adapter instance pointer * @error_code: error classification * * Puts out an error log when driver is unable to offload iscsi connection * due to license restrictions */ static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code) { … } /** * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification * @ep: endpoint (transport identifier) structure * @action: action, ARM or DISARM. For now only ARM_CQE is used * * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt * the driver. EQ event is generated CQ index is hit or at least 1 CQ is * outstanding and on chip timer expires */ int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) { … } /** * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer * @bnx2i_conn: iscsi connection on which RQ event occurred * @ptr: driver buffer to which RQ buffer contents is to * be copied * @len: length of valid data inside RQ buf * * Copies RQ buffer contents from shared (DMA'able) memory region to * driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and * scsi sense info */ void bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len) { … } static void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn) { … } /** * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell * @bnx2i_conn: iscsi connection on which event to post * @count: number of RQ buffer being posted to chip * * No need to ring hardware doorbell for 57710 family of devices */ void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count) { … } /** * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine * @bnx2i_conn: iscsi connection to which new SQ entries belong * @count: number of SQ WQEs to post * * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family * of devices. For 5706/5708/5709 new SQ WQE count is written into the * doorbell register */ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) { … } /** * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters * @bnx2i_conn: iscsi connection to which new SQ entries belong * @count: number of SQ WQEs to post * * this routine will update SQ driver parameters and ring the doorbell */ static void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn, int count) { … } /** * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware * @bnx2i_conn: iscsi connection * @task: transport layer's command structure pointer which is requesting * a WQE to sent to chip for further processing * * prepare and post an iSCSI Login request WQE to CNIC firmware */ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn, struct iscsi_task *task) { … } /** * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware * @bnx2i_conn: iscsi connection * @mtask: driver command structure which is requesting * a WQE to sent to chip for further processing * * prepare and post an iSCSI Login request WQE to CNIC firmware */ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, struct iscsi_task *mtask) { … } /** * bnx2i_send_iscsi_text - post iSCSI text WQE to hardware * @bnx2i_conn: iscsi connection * @mtask: driver command structure which is requesting * a WQE to sent to chip for further processing * * prepare and post an iSCSI Text request WQE to CNIC firmware */ int bnx2i_send_iscsi_text(struct bnx2i_conn *bnx2i_conn, struct iscsi_task *mtask) { … } /** * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware * @bnx2i_conn: iscsi connection * @cmd: driver command structure which is requesting * a WQE to sent to chip for further processing * * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware */ int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn, struct bnx2i_cmd *cmd) { … } /** * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware * @bnx2i_conn: iscsi connection * @task: transport layer's command structure pointer which is * requesting a WQE to sent to chip for further processing * @datap: payload buffer pointer * @data_len: payload data length * @unsol: indicated whether nopout pdu is unsolicited pdu or * in response to target's NOPIN w/ TTT != FFFFFFFF * * prepare and post a nopout request WQE to CNIC firmware */ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, struct iscsi_task *task, char *datap, int data_len, int unsol) { … } /** * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware * @bnx2i_conn: iscsi connection * @task: transport layer's command structure pointer which is * requesting a WQE to sent to chip for further processing * * prepare and post logout request WQE to CNIC firmware */ int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn, struct iscsi_task *task) { … } /** * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware * @conn: iscsi connection which requires iscsi parameter update * * sends down iSCSI Conn Update request to move iSCSI conn to FFP */ void bnx2i_update_iscsi_conn(struct iscsi_conn *conn) { … } /** * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware * @t: timer context used to fetch the endpoint (transport * handle) structure pointer * * routine to handle connection offload/destroy request timeout */ void bnx2i_ep_ofld_timer(struct timer_list *t) { … } static int bnx2i_power_of2(u32 val) { … } /** * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request * @hba: adapter structure pointer * @cmd: driver command structure which is requesting * a WQE to sent to chip for further processing * * prepares and posts CONN_OFLD_REQ1/2 KWQE */ void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) { … } /** * bnx2i_send_conn_destroy - initiates iscsi connection teardown process * @hba: adapter structure pointer * @ep: endpoint (transport identifier) structure * * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate * iscsi connection context clean-up process */ int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process * @hba: adapter structure pointer * @ep: endpoint (transport identifier) structure * * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE */ static int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation * @hba: adapter structure pointer * @ep: endpoint (transport identifier) structure * * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE */ static int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process * * @hba: adapter structure pointer * @ep: endpoint (transport identifier) structure * * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE */ int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * setup_qp_page_tables - iscsi QP page table setup function * @ep: endpoint (transport identifier) structure * * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires * 64-bit address in big endian format. Whereas 10G/sec (57710) requires * PT in little endian format */ static void setup_qp_page_tables(struct bnx2i_endpoint *ep) { … } /** * bnx2i_alloc_qp_resc - allocates required resources for QP. * @hba: adapter structure pointer * @ep: endpoint (transport identifier) structure * * Allocate QP (transport layer for iSCSI connection) resources, DMA'able * memory for SQ/RQ/CQ and page tables. EP structure elements such * as producer/consumer indexes/pointers, queue sizes and page table * contents are setup */ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_free_qp_resc - free memory resources held by QP * @hba: adapter structure pointer * @ep: endpoint (transport identifier) structure * * Free QP resources - SQ/RQ/CQ memory and page tables. */ void bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { … } /** * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w * @hba: adapter structure pointer * * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w * This results in iSCSi support validation and on-chip context manager * initialization. Firmware completes this handshake with a CQE carrying * the result of iscsi support validation. Parameter carried by * iscsi init request determines the number of offloaded connection and * tolerance level for iscsi protocol violation this hba/chip can support */ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) { … } /** * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. * @session: iscsi session * @bnx2i_conn: bnx2i connection * @cqe: pointer to newly DMA'ed CQE entry for processing * * process SCSI CMD Response CQE & complete the request to SCSI-ML */ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_login_resp - this function handles iscsi login response * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process Login Response CQE & complete it to open-iscsi user daemon */ static int bnx2i_process_login_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_text_resp - this function handles iscsi text response * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI Text Response CQE& complete it to open-iscsi user daemon */ static int bnx2i_process_text_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_tmf_resp - this function handles iscsi TMF response * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI TMF Response CQE and wake up the driver eh thread. */ static int bnx2i_process_tmf_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_logout_resp - this function handles iscsi logout response * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI Logout Response CQE & make function call to * notify the user daemon. */ static int bnx2i_process_logout_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI NOPIN local completion CQE, frees IIT and command structures */ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd * @bnx2i_conn: iscsi connection * * Firmware advances RQ producer index for every unsolicited PDU even if * payload data length is '0'. This function makes corresponding * adjustments on the driver side to match this f/w behavior */ static void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn) { … } /** * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI target's proactive iSCSI NOPIN request */ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_async_mesg - this function handles iscsi async message * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI ASYNC Message */ static void bnx2i_process_async_mesg(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_reject_mesg - process iscsi reject pdu * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process iSCSI REJECT message */ static void bnx2i_process_reject_mesg(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion * @session: iscsi session pointer * @bnx2i_conn: iscsi connection pointer * @cqe: pointer to newly DMA'ed CQE entry for processing * * process command cleanup response CQE during conn shutdown or error recovery */ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct cqe *cqe) { … } /** * bnx2i_percpu_io_thread - thread per cpu for ios * * @arg: ptr to bnx2i_percpu_info structure */ int bnx2i_percpu_io_thread(void *arg) { … } /** * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread * @session: iscsi session * @bnx2i_conn: bnx2i connection * @cqe: pointer to newly DMA'ed CQE entry for processing * * this function is called by generic KCQ handler to queue all pending cmd * completion CQEs * * The implementation is to queue the cmd response based on the * last recorded command for the given connection. The * cpu_id gets recorded upon task_xmit. No out-of-order completion! */ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, struct bnx2i_conn *bnx2i_conn, struct bnx2i_nop_in_msg *cqe) { … } /** * bnx2i_process_new_cqes - process newly DMA'ed CQE's * @bnx2i_conn: bnx2i connection * * this function is called by generic KCQ handler to process all pending CQE's */ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) { … } /** * bnx2i_fastpath_notification - process global event queue (KCQ) * @hba: adapter structure pointer * @new_cqe_kcqe: pointer to newly DMA'ed KCQE entry * * Fast path event notification handler, KCQ entry carries context id * of the connection that has 1 or more pending CQ entries */ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, struct iscsi_kcqe *new_cqe_kcqe) { … } /** * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE * @hba: adapter structure pointer * @update_kcqe: kcqe pointer * * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration */ static void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba, struct iscsi_kcqe *update_kcqe) { … } /** * bnx2i_recovery_que_add_conn - add connection to recovery queue * @hba: adapter structure pointer * @bnx2i_conn: iscsi connection * * Add connection to recovery queue and schedule adapter eh worker */ static void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba, struct bnx2i_conn *bnx2i_conn) { … } /** * bnx2i_process_tcp_error - process error notification on a given connection * * @hba: adapter structure pointer * @tcp_err: tcp error kcqe pointer * * handles tcp level error notifications from FW. */ static void bnx2i_process_tcp_error(struct bnx2i_hba *hba, struct iscsi_kcqe *tcp_err) { … } /** * bnx2i_process_iscsi_error - process error notification on a given connection * @hba: adapter structure pointer * @iscsi_err: iscsi error kcqe pointer * * handles iscsi error notifications from the FW. Firmware based in initial * handshake classifies iscsi protocol / TCP rfc violation into either * warning or error indications. If indication is of "Error" type, driver * will initiate session recovery for that connection/session. For * "Warning" type indication, driver will put out a system log message * (there will be only one message for each type for the life of the * session, this is to avoid un-necessarily overloading the system) */ static void bnx2i_process_iscsi_error(struct bnx2i_hba *hba, struct iscsi_kcqe *iscsi_err) { … } /** * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion * @hba: adapter structure pointer * @conn_destroy: conn destroy kcqe pointer * * handles connection destroy completion request. */ static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba, struct iscsi_kcqe *conn_destroy) { … } /** * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion * @hba: adapter structure pointer * @ofld_kcqe: conn offload kcqe pointer * * handles initial connection offload completion, ep_connect() thread is * woken-up to continue with LLP connect process */ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, struct iscsi_kcqe *ofld_kcqe) { … } /** * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE * @context: adapter structure pointer * @kcqe: kcqe pointer * @num_cqe: number of kcqes to process * * Generic KCQ event handler/dispatcher */ static void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[], u32 num_cqe) { … } /** * bnx2i_indicate_netevent - Generic netdev event handler * @context: adapter structure pointer * @event: event type * @vlan_id: vlans id - associated vlan id with this event * * Handles four netdev events, NETDEV_UP, NETDEV_DOWN, * NETDEV_GOING_DOWN and NETDEV_CHANGE */ static void bnx2i_indicate_netevent(void *context, unsigned long event, u16 vlan_id) { … } /** * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion * @cm_sk: cnic sock structure pointer * * function callback exported via bnx2i - cnic driver interface to * indicate completion of option-2 TCP connect request. */ static void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk) { … } /** * bnx2i_cm_close_cmpl - process tcp conn close completion * @cm_sk: cnic sock structure pointer * * function callback exported via bnx2i - cnic driver interface to * indicate completion of option-2 graceful TCP connect shutdown */ static void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk) { … } /** * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion * @cm_sk: cnic sock structure pointer * * function callback exported via bnx2i - cnic driver interface to * indicate completion of option-2 abortive TCP connect termination */ static void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk) { … } /** * bnx2i_cm_remote_close - process received TCP FIN * @cm_sk: cnic sock structure pointer * * function callback exported via bnx2i - cnic driver interface to indicate * async TCP events such as FIN */ static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk) { … } /** * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup * @cm_sk: cnic sock structure pointer * * function callback exported via bnx2i - cnic driver interface to * indicate async TCP events (RST) sent by the peer. */ static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) { … } static int bnx2i_send_nl_mesg(void *context, u32 msg_type, char *buf, u16 buflen) { … } /* * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure * carrying callback function pointers */ struct cnic_ulp_ops bnx2i_cnic_cb = …; /** * bnx2i_map_ep_dbell_regs - map connection doorbell registers * @ep: bnx2i endpoint * * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these * register in BAR #0. Whereas in 57710 these register are accessed by * mapping BAR #1 */ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep) { … }