diff options
Diffstat (limited to 'drivers/scsi/bnx2i')
-rw-r--r-- | drivers/scsi/bnx2i/57xx_iscsi_constants.h | 3 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/57xx_iscsi_hsi.h | 3 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i.h | 15 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_hwi.c | 96 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_init.c | 108 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_iscsi.c | 148 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_sysfs.c | 3 |
7 files changed, 195 insertions, 181 deletions
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h index 1b6f86b2482..30e6bdbd65a 100644 --- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h @@ -1,12 +1,13 @@ /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI * - * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom 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 (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #ifndef __57XX_ISCSI_CONSTANTS_H_ #define __57XX_ISCSI_CONSTANTS_H_ diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h index 36af1afef9b..dad6c8a3431 100644 --- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h +++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h @@ -1,12 +1,13 @@ /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. * - * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom 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 (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #ifndef __57XX_ISCSI_HSI_LINUX_LE__ #define __57XX_ISCSI_HSI_LINUX_LE__ diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index a44b1b33fa1..e1ca5fe7e6b 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -1,6 +1,6 @@ /* bnx2i.h: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -9,6 +9,7 @@ * the Free Software Foundation. * * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #ifndef _BNX2I_H_ @@ -649,6 +650,7 @@ enum { EP_STATE_OFLD_FAILED = 0x8000000, EP_STATE_CONNECT_FAILED = 0x10000000, EP_STATE_DISCONN_TIMEDOUT = 0x20000000, + EP_STATE_OFLD_FAILED_CID_BUSY = 0x80000000, }; /** @@ -717,14 +719,11 @@ extern struct device_attribute *bnx2i_dev_attributes[]; * Function Prototypes */ extern void bnx2i_identify_device(struct bnx2i_hba *hba); -extern void bnx2i_register_device(struct bnx2i_hba *hba); extern void bnx2i_ulp_init(struct cnic_dev *dev); extern void bnx2i_ulp_exit(struct cnic_dev *dev); extern void bnx2i_start(void *handle); extern void bnx2i_stop(void *handle); -extern void bnx2i_reg_dev_all(void); -extern void bnx2i_unreg_dev_all(void); extern struct bnx2i_hba *get_adapter_list_head(void); struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, @@ -761,11 +760,11 @@ extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn, struct iscsi_task *mtask); extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd); -extern void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep); -extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn); -extern void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, +extern int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep); +extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn); +extern int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep); extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep); diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 2f9622ebbd8..96505e3ab98 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1,6 +1,6 @@ /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -9,6 +9,7 @@ * the Free Software Foundation. * * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #include <linux/gfp.h> @@ -385,6 +386,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, struct bnx2i_cmd *bnx2i_cmd; struct bnx2i_tmf_request *tmfabort_wqe; u32 dword; + u32 scsi_lun[2]; bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data; tmfabort_hdr = (struct iscsi_tm *)mtask->hdr; @@ -426,7 +428,10 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, default: tmfabort_wqe->ref_itt = RESERVED_ITT; } - memcpy(tmfabort_wqe->lun, tmfabort_hdr->lun, sizeof(struct scsi_lun)); + memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun)); + tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); + tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); + tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn); tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma; @@ -697,10 +702,11 @@ void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate * iscsi connection context clean-up process */ -void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) +int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { struct kwqe *kwqe_arr[2]; struct iscsi_kwqe_conn_destroy conn_cleanup; + int rc = -EINVAL; memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy)); @@ -717,7 +723,9 @@ void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) kwqe_arr[0] = (struct kwqe *) &conn_cleanup; if (hba->cnic && hba->cnic->submit_kwqes) - hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1); + rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1); + + return rc; } @@ -728,8 +736,8 @@ void bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) * * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE */ -static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) +static int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) { struct kwqe *kwqe_arr[2]; struct iscsi_kwqe_conn_offload1 ofld_req1; @@ -737,6 +745,7 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, dma_addr_t dma_addr; int num_kwqes = 2; u32 *ptbl; + int rc = -EINVAL; ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1; ofld_req1.hdr.flags = @@ -774,7 +783,9 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, ofld_req2.num_additional_wqes = 0; if (hba->cnic && hba->cnic->submit_kwqes) - hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); + rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); + + return rc; } @@ -785,8 +796,8 @@ static void bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, * * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE */ -static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) +static int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) { struct kwqe *kwqe_arr[5]; struct iscsi_kwqe_conn_offload1 ofld_req1; @@ -795,6 +806,7 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, dma_addr_t dma_addr; int num_kwqes = 2; u32 *ptbl; + int rc = -EINVAL; ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1; ofld_req1.hdr.flags = @@ -840,7 +852,9 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, num_kwqes += 1; if (hba->cnic && hba->cnic->submit_kwqes) - hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); + rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); + + return rc; } /** @@ -851,12 +865,16 @@ static void bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, * * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE */ -void bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) +int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { + int rc; + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) - bnx2i_5771x_send_conn_ofld_req(hba, ep); + rc = bnx2i_5771x_send_conn_ofld_req(hba, ep); else - bnx2i_570x_send_conn_ofld_req(hba, ep); + rc = bnx2i_570x_send_conn_ofld_req(hba, ep); + + return rc; } @@ -1513,7 +1531,7 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session, task = iscsi_itt_to_task(conn, nop_in->itt & ISCSI_NOP_IN_MSG_INDEX); if (task) - iscsi_put_task(task); + __iscsi_put_task(task); spin_unlock(&session->lock); } @@ -1549,11 +1567,9 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, struct iscsi_task *task; struct bnx2i_nop_in_msg *nop_in; struct iscsi_nopin *hdr; - u32 itt; int tgt_async_nop = 0; nop_in = (struct bnx2i_nop_in_msg *)cqe; - itt = nop_in->itt & ISCSI_NOP_IN_MSG_INDEX; spin_lock(&session->lock); hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr; @@ -1563,7 +1579,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn); hdr->ttt = cpu_to_be32(nop_in->ttt); - if (itt == (u16) RESERVED_ITT) { + if (nop_in->itt == (u16) RESERVED_ITT) { bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); hdr->itt = RESERVED_ITT; tgt_async_nop = 1; @@ -1571,7 +1587,8 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, } /* this is a response to one of our nop-outs */ - task = iscsi_itt_to_task(conn, itt); + task = iscsi_itt_to_task(conn, + (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX)); if (task) { hdr->flags = ISCSI_FLAG_CMD_FINAL; hdr->itt = task->hdr->itt; @@ -1721,9 +1738,18 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) break; - if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) + if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) { + if (nopin->op_code == ISCSI_OP_NOOP_IN && + nopin->itt == (u16) RESERVED_ITT) { + printk(KERN_ALERT "bnx2i: Unsolicited " + "NOP-In detected for suspended " + "connection dev=%s!\n", + bnx2i_conn->hba->netdev->name); + bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); + goto cqe_out; + } break; - + } tgt_async_msg = 0; switch (nopin->op_code) { @@ -1770,10 +1796,9 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", nopin->op_code); } - if (!tgt_async_msg) bnx2i_conn->ep->num_active_cmds--; - +cqe_out: /* clear out in production version only, till beta keep opcode * field intact, will be helpful in debugging (context dump) * nopin->op_code = 0; @@ -2154,11 +2179,24 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, } if (ofld_kcqe->completion_status) { + ep->state = EP_STATE_OFLD_FAILED; if (ofld_kcqe->completion_status == ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) - printk(KERN_ALERT "bnx2i: unable to allocate" - " iSCSI context resources\n"); - ep->state = EP_STATE_OFLD_FAILED; + printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable " + "to allocate iSCSI context resources\n", + hba->netdev->name); + else if (ofld_kcqe->completion_status == + ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE) + printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " + "opcode\n", hba->netdev->name); + else if (ofld_kcqe->completion_status == + ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) + /* error status code valid only for 5771x chipset */ + ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; + else + printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " + "error code %d\n", hba->netdev->name, + ofld_kcqe->completion_status); } else { ep->state = EP_STATE_OFLD_COMPL; cid_addr = ofld_kcqe->iscsi_conn_context_id; @@ -2339,10 +2377,14 @@ static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk) static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) { struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; + u32 old_state = ep->state; ep->state = EP_STATE_TCP_RST_RCVD; - if (ep->conn) - bnx2i_recovery_que_add_conn(ep->hba, ep->conn); + if (old_state == EP_STATE_DISCONN_START) + wake_up_interruptible(&ep->ofld_wait); + else + if (ep->conn) + bnx2i_recovery_que_add_conn(ep->hba, ep->conn); } diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 50c2aa3b8eb..72a7b2d4a43 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -1,6 +1,6 @@ /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -9,6 +9,7 @@ * the Free Software Foundation. * * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #include "bnx2i.h" @@ -17,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.1.3" -#define DRV_MODULE_RELDATE "Aug 10, 2010" +#define DRV_MODULE_VERSION "2.6.2.2" +#define DRV_MODULE_RELDATE "Nov 23, 2010" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ @@ -65,8 +66,6 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size"); u64 iscsi_error_mask = 0x00; -static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) ; - /** * bnx2i_identify_device - identifies NetXtreme II device type @@ -211,13 +210,24 @@ void bnx2i_stop(void *handle) { struct bnx2i_hba *hba = handle; int conns_active; + int wait_delay = 1 * HZ; /* check if cleanup happened in GOING_DOWN context */ - if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN, - &hba->adapter_state)) + if (!test_and_set_bit(ADAPTER_STATE_GOING_DOWN, + &hba->adapter_state)) { iscsi_host_for_each_session(hba->shost, bnx2i_drop_session); - + wait_delay = hba->hba_shutdown_tmo; + } + /* Wait for inflight offload connection tasks to complete before + * proceeding. Forcefully terminate all connection recovery in + * progress at the earliest, either in bind(), send_pdu(LOGIN), + * or conn_start() + */ + wait_event_interruptible_timeout(hba->eh_wait, + (list_empty(&hba->ep_ofld_list) && + list_empty(&hba->ep_destroy_list)), + 10 * HZ); /* Wait for all endpoints to be torn down, Chip will be reset once * control returns to network driver. So it is required to cleanup and * release all connection resources before returning from this routine. @@ -226,7 +236,7 @@ void bnx2i_stop(void *handle) conns_active = hba->ofld_conns_active; wait_event_interruptible_timeout(hba->eh_wait, (hba->ofld_conns_active != conns_active), - hba->hba_shutdown_tmo); + wait_delay); if (hba->ofld_conns_active == conns_active) break; } @@ -235,88 +245,10 @@ void bnx2i_stop(void *handle) /* This flag should be cleared last so that ep_disconnect() gracefully * cleans up connection context */ + clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); } -/** - * bnx2i_register_device - register bnx2i adapter instance with the cnic driver - * @hba: Adapter instance to register - * - * registers bnx2i adapter instance with the cnic driver while holding the - * adapter structure lock - */ -void bnx2i_register_device(struct bnx2i_hba *hba) -{ - int rc; - - if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) || - test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - return; - } - - rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba); - - if (!rc) - set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); -} - - -/** - * bnx2i_reg_dev_all - registers all adapter instances with the cnic driver - * - * registers all bnx2i adapter instances with the cnic driver while holding - * the global resource lock - */ -void bnx2i_reg_dev_all(void) -{ - struct bnx2i_hba *hba, *temp; - - mutex_lock(&bnx2i_dev_lock); - list_for_each_entry_safe(hba, temp, &adapter_list, link) - bnx2i_register_device(hba); - mutex_unlock(&bnx2i_dev_lock); -} - - -/** - * bnx2i_unreg_one_device - unregister adapter instance with the cnic driver - * @hba: Adapter instance to unregister - * - * registers bnx2i adapter instance with the cnic driver while holding - * the adapter structure lock - */ -static void bnx2i_unreg_one_device(struct bnx2i_hba *hba) -{ - if (hba->ofld_conns_active || - !test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) || - test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) - return; - - hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); - - /* ep_disconnect could come before NETDEV_DOWN, driver won't - * see NETDEV_DOWN as it already unregistered itself. - */ - hba->adapter_state = 0; - clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); -} - -/** - * bnx2i_unreg_dev_all - unregisters all bnx2i instances with the cnic driver - * - * unregisters all bnx2i adapter instances with the cnic driver while holding - * the global resource lock - */ -void bnx2i_unreg_dev_all(void) -{ - struct bnx2i_hba *hba, *temp; - - mutex_lock(&bnx2i_dev_lock); - list_for_each_entry_safe(hba, temp, &adapter_list, link) - bnx2i_unreg_one_device(hba); - mutex_unlock(&bnx2i_dev_lock); -} - /** * bnx2i_init_one - initialize an adapter instance and allocate memory resources diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index fb50efbce08..f0dce26593e 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1,7 +1,7 @@ /* * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2006 - 2009 Broadcom Corporation + * Copyright (c) 2006 - 2010 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * @@ -10,6 +10,7 @@ * the Free Software Foundation. * * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #include <linux/slab.h> @@ -411,7 +412,9 @@ static void bnx2i_free_ep(struct iscsi_endpoint *ep) bnx2i_ep->state = EP_STATE_IDLE; bnx2i_ep->hba->ofld_conns_active--; - bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid); + if (bnx2i_ep->ep_iscsi_cid != (u16) -1) + bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid); + if (bnx2i_ep->conn) { bnx2i_ep->conn->ep = NULL; bnx2i_ep->conn = NULL; @@ -1383,6 +1386,12 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, ep = iscsi_lookup_endpoint(transport_fd); if (!ep) return -EINVAL; + /* + * Forcefully terminate all in progress connection recovery at the + * earliest, either in bind(), send_pdu(LOGIN), or conn_start() + */ + if (bnx2i_adapter_ready(hba)) + return -EIO; bnx2i_ep = ep->dd_data; if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) || @@ -1404,7 +1413,6 @@ static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, hba->netdev->name); return -EEXIST; } - bnx2i_ep->conn = bnx2i_conn; bnx2i_conn->ep = bnx2i_ep; bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid; @@ -1461,21 +1469,28 @@ static int bnx2i_conn_get_param(struct iscsi_cls_conn *cls_conn, struct bnx2i_conn *bnx2i_conn = conn->dd_data; int len = 0; + if (!(bnx2i_conn && bnx2i_conn->ep && bnx2i_conn->ep->hba)) + goto out; + switch (param) { case ISCSI_PARAM_CONN_PORT: - if (bnx2i_conn->ep) + mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock); + if (bnx2i_conn->ep->cm_sk) len = sprintf(buf, "%hu\n", bnx2i_conn->ep->cm_sk->dst_port); + mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock); break; case ISCSI_PARAM_CONN_ADDRESS: - if (bnx2i_conn->ep) + mutex_lock(&bnx2i_conn->ep->hba->net_dev_lock); + if (bnx2i_conn->ep->cm_sk) len = sprintf(buf, "%pI4\n", &bnx2i_conn->ep->cm_sk->dst_ip); + mutex_unlock(&bnx2i_conn->ep->hba->net_dev_lock); break; default: return iscsi_conn_get_param(cls_conn, param, buf); } - +out: return len; } @@ -1599,8 +1614,6 @@ static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr) struct bnx2i_hba *hba; struct cnic_dev *cnic = NULL; - bnx2i_reg_dev_all(); - hba = get_adapter_list_head(); if (hba && hba->cnic) cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI); @@ -1640,18 +1653,26 @@ no_nx2_route: static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) { - if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) + if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk) hba->cnic->cm_destroy(ep->cm_sk); - if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state)) - ep->state = EP_STATE_DISCONN_COMPL; - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) && ep->state == EP_STATE_DISCONN_TIMEDOUT) { - printk(KERN_ALERT "bnx2i - ERROR - please submit GRC Dump," - " NW/PCIe trace, driver msgs to developers" - " for analysis\n"); - return 1; + if (ep->conn && ep->conn->cls_conn && + ep->conn->cls_conn->dd_data) { + struct iscsi_conn *conn = ep->conn->cls_conn->dd_data; + + /* Must suspend all rx queue activity for this ep */ + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + } + /* CONN_DISCONNECT timeout may or may not be an issue depending + * on what transcribed in TCP layer, different targets behave + * differently + */ + printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, " + "please submit GRC Dump, NW/PCIe trace, " + "driver msgs to developers for analysis\n", + hba->netdev->name); } ep->state = EP_STATE_CLEANUP_START; @@ -1664,7 +1685,9 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, bnx2i_ep_destroy_list_add(hba, ep); /* destroy iSCSI context, wait for it to complete */ - bnx2i_send_conn_destroy(hba, ep); + if (bnx2i_send_conn_destroy(hba, ep)) + ep->state = EP_STATE_CLEANUP_CMPL; + wait_event_interruptible(ep->ofld_wait, (ep->state != EP_STATE_CLEANUP_START)); @@ -1711,8 +1734,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, if (shost) { /* driver is given scsi host to work with */ hba = iscsi_host_priv(shost); - /* Register the device with cnic if not already done so */ - bnx2i_register_device(hba); } else /* * check if the given destination can be reached through @@ -1720,13 +1741,17 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, */ hba = bnx2i_check_route(dst_addr); - if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) { + if (!hba) { rc = -EINVAL; goto nohba; } + mutex_lock(&hba->net_dev_lock); + if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) { + rc = -EPERM; + goto check_busy; + } cnic = hba->cnic; - mutex_lock(&hba->net_dev_lock); ep = bnx2i_alloc_ep(hba); if (!ep) { rc = -ENOMEM; @@ -1734,23 +1759,21 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, } bnx2i_ep = ep->dd_data; - if (bnx2i_adapter_ready(hba)) { - rc = -EPERM; - goto net_if_down; - } - bnx2i_ep->num_active_cmds = 0; iscsi_cid = bnx2i_alloc_iscsi_cid(hba); if (iscsi_cid == -1) { - printk(KERN_ALERT "alloc_ep: unable to allocate iscsi cid\n"); + printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " + "iscsi cid\n", hba->netdev->name); rc = -ENOMEM; - goto iscsi_cid_err; + bnx2i_free_ep(ep); + goto check_busy; } bnx2i_ep->hba_age = hba->age; rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep); if (rc != 0) { - printk(KERN_ALERT "bnx2i: ep_conn, alloc QP resc error\n"); + printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error" + "\n", hba->netdev->name); rc = -ENOMEM; goto qp_resc_err; } @@ -1765,7 +1788,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; add_timer(&bnx2i_ep->ofld_timer); - bnx2i_send_conn_ofld_req(hba, bnx2i_ep); + if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) { + if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) { + printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n", + hba->netdev->name, bnx2i_ep->ep_iscsi_cid); + rc = -EBUSY; + } else + rc = -ENOSPC; + printk(KERN_ALERT "bnx2i (%s): unable to send conn offld kwqe" + "\n", hba->netdev->name); + bnx2i_ep_ofld_list_del(hba, bnx2i_ep); + goto conn_failed; + } /* Wait for CNIC hardware to setup conn context and return 'cid' */ wait_event_interruptible(bnx2i_ep->ofld_wait, @@ -1778,7 +1812,12 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, bnx2i_ep_ofld_list_del(hba, bnx2i_ep); if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) { - rc = -ENOSPC; + if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) { + printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n", + hba->netdev->name, bnx2i_ep->ep_iscsi_cid); + rc = -EBUSY; + } else + rc = -ENOSPC; goto conn_failed; } @@ -1786,7 +1825,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep); if (rc) { rc = -EINVAL; - goto conn_failed; + /* Need to terminate and cleanup the connection */ + goto release_ep; } bnx2i_ep->cm_sk->rcv_buf = 256 * 1024; @@ -1830,15 +1870,12 @@ release_ep: return ERR_PTR(rc); } conn_failed: -net_if_down: -iscsi_cid_err: bnx2i_free_qp_resc(hba, bnx2i_ep); qp_resc_err: bnx2i_free_ep(ep); check_busy: mutex_unlock(&hba->net_dev_lock); nohba: - bnx2i_unreg_dev_all(); return ERR_PTR(rc); } @@ -1898,12 +1935,13 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) cnic_dev_10g = 1; switch (bnx2i_ep->state) { - case EP_STATE_CONNECT_START: + case EP_STATE_CONNECT_FAILED: case EP_STATE_CLEANUP_FAILED: case EP_STATE_OFLD_FAILED: case EP_STATE_DISCONN_TIMEDOUT: ret = 0; break; + case EP_STATE_CONNECT_START: case EP_STATE_CONNECT_COMPL: case EP_STATE_ULP_UPDATE_START: case EP_STATE_ULP_UPDATE_COMPL: @@ -1914,13 +1952,10 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) ret = 1; break; case EP_STATE_TCP_RST_RCVD: - ret = 0; - break; - case EP_STATE_CONNECT_FAILED: if (cnic_dev_10g) - ret = 1; - else ret = 0; + else + ret = 1; break; default: ret = 0; @@ -1953,7 +1988,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) if (!cnic) return 0; - if (bnx2i_ep->state == EP_STATE_IDLE) + if (bnx2i_ep->state == EP_STATE_IDLE || + bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) return 0; if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) @@ -1979,9 +2015,10 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) if (session->state == ISCSI_STATE_LOGGING_OUT) { if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) { /* Logout sent, but no resp */ - printk(KERN_ALERT "bnx2i - WARNING " - "logout response was not " - "received!\n"); + printk(KERN_ALERT "bnx2i (%s): WARNING" + " logout response was not " + "received!\n", + bnx2i_ep->hba->netdev->name); } else if (bnx2i_ep->state == EP_STATE_LOGOUT_RESP_RCVD) close = 1; @@ -1999,9 +2036,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) else close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); - /* No longer allow CFC delete if cm_close/abort fails the request */ if (close_ret) - printk(KERN_ALERT "bnx2i: %s close/abort(%d) returned %d\n", + printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n", bnx2i_ep->hba->netdev->name, close, close_ret); else /* wait for option-2 conn teardown */ @@ -2015,7 +2051,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) destroy_conn: bnx2i_ep_active_list_del(hba, bnx2i_ep); if (bnx2i_tear_down_conn(hba, bnx2i_ep)) - ret = -EINVAL; + return -EINVAL; out: bnx2i_ep->state = EP_STATE_IDLE; return ret; @@ -2054,14 +2090,17 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) mutex_lock(&hba->net_dev_lock); - if (bnx2i_ep->state == EP_STATE_IDLE) - goto return_bnx2i_ep; + if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) + goto out; - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) + if (bnx2i_ep->state == EP_STATE_IDLE) goto free_resc; - if (bnx2i_ep->hba_age != hba->age) + if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) || + (bnx2i_ep->hba_age != hba->age)) { + bnx2i_ep_active_list_del(hba, bnx2i_ep); goto free_resc; + } /* Do all chip cleanup here */ if (bnx2i_hw_ep_disconnect(bnx2i_ep)) { @@ -2070,14 +2109,13 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) } free_resc: bnx2i_free_qp_resc(hba, bnx2i_ep); -return_bnx2i_ep: + if (bnx2i_conn) bnx2i_conn->ep = NULL; bnx2i_free_ep(ep); +out: mutex_unlock(&hba->net_dev_lock); - if (!hba->ofld_conns_active) - bnx2i_unreg_dev_all(); wake_up_interruptible(&hba->eh_wait); } diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c index 96426b751eb..9174196d903 100644 --- a/drivers/scsi/bnx2i/bnx2i_sysfs.c +++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c @@ -1,12 +1,13 @@ /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. * - * Copyright (c) 2004 - 2009 Broadcom Corporation + * Copyright (c) 2004 - 2010 Broadcom 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 (anilgv@broadcom.com) + * Maintained by: Eddie Wai (eddie.wai@broadcom.com) */ #include "bnx2i.h" |