diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-23 14:13:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-23 14:13:11 -0400 |
commit | d4e06701b89286a306b31e20ec69a904fae374a1 (patch) | |
tree | f6adefd65b021ccddb7655109ea8b9ab4e714292 /drivers/scsi/bnx2i | |
parent | e4980371059ca4a81ccdcb4381c41af8869ca711 (diff) | |
parent | 87045b033a62777337ae4aa62834876da09b5fb5 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (77 commits)
[SCSI] fix crash in scsi_dispatch_cmd()
[SCSI] sr: check_events() ignore GET_EVENT when TUR says otherwise
[SCSI] bnx2i: Fixed kernel panic due to illegal usage of sc->request->cpu
[SCSI] bfa: Update the driver version to 3.0.2.1
[SCSI] bfa: Driver and BSG enhancements.
[SCSI] bfa: Added support to query PHY.
[SCSI] bfa: Added HBA diagnostics support.
[SCSI] bfa: Added support for flash configuration
[SCSI] bfa: Added support to obtain SFP info.
[SCSI] bfa: Added support for CEE info and stats query.
[SCSI] bfa: Extend BSG interface.
[SCSI] bfa: FCS bug fixes.
[SCSI] bfa: DMA memory allocation enhancement.
[SCSI] bfa: Brocade-1860 Fabric Adapter vHBA support.
[SCSI] bfa: Brocade-1860 Fabric Adapter PLL init fixes.
[SCSI] bfa: Added Fabric Assigned Address(FAA) support
[SCSI] bfa: IOC bug fixes.
[SCSI] bfa: Enable ASIC block configuration and query.
[SCSI] bnx2i: Updated copyright and bump version
[SCSI] bnx2i: Modified to skip CNIC registration if iSCSI is not supported
...
Fix up some trivial conflicts in:
- drivers/scsi/bnx2fc/{bnx2fc.h,bnx2fc_fcoe.c}:
Crazy broadcom version number conflicts
- drivers/target/tcm_fc/tfc_cmd.c
Just trivial cleanups done on adjacent lines
Diffstat (limited to 'drivers/scsi/bnx2i')
-rw-r--r-- | drivers/scsi/bnx2i/57xx_iscsi_constants.h | 2 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/57xx_iscsi_hsi.h | 2 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i.h | 33 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_hwi.c | 199 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_init.c | 153 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_iscsi.c | 38 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_sysfs.c | 2 |
7 files changed, 367 insertions, 62 deletions
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h index 15673cc786ff..57515f1f1690 100644 --- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI | 1 | /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI |
2 | * | 2 | * |
3 | * Copyright (c) 2006 - 2010 Broadcom Corporation | 3 | * Copyright (c) 2006 - 2011 Broadcom Corporation |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h index 71890a063cd3..72118db89a20 100644 --- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h +++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. | 1 | /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. |
2 | * | 2 | * |
3 | * Copyright (c) 2006 - 2010 Broadcom Corporation | 3 | * Copyright (c) 2006 - 2011 Broadcom Corporation |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index e7cb7ecf6847..dc5700765db4 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* bnx2i.h: Broadcom NetXtreme II iSCSI driver. | 1 | /* bnx2i.h: Broadcom NetXtreme II iSCSI driver. |
2 | * | 2 | * |
3 | * Copyright (c) 2006 - 2010 Broadcom Corporation | 3 | * Copyright (c) 2006 - 2011 Broadcom Corporation |
4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. | 4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. |
5 | * Copyright (c) 2007, 2008 Mike Christie | 5 | * Copyright (c) 2007, 2008 Mike Christie |
6 | * | 6 | * |
@@ -22,11 +22,14 @@ | |||
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/delay.h> | ||
25 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
26 | #include <linux/in.h> | 27 | #include <linux/in.h> |
27 | #include <linux/kfifo.h> | 28 | #include <linux/kfifo.h> |
28 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
29 | #include <linux/completion.h> | 30 | #include <linux/completion.h> |
31 | #include <linux/kthread.h> | ||
32 | #include <linux/cpu.h> | ||
30 | 33 | ||
31 | #include <scsi/scsi_cmnd.h> | 34 | #include <scsi/scsi_cmnd.h> |
32 | #include <scsi/scsi_device.h> | 35 | #include <scsi/scsi_device.h> |
@@ -202,10 +205,13 @@ struct io_bdt { | |||
202 | /** | 205 | /** |
203 | * bnx2i_cmd - iscsi command structure | 206 | * bnx2i_cmd - iscsi command structure |
204 | * | 207 | * |
208 | * @hdr: iSCSI header | ||
209 | * @conn: iscsi_conn pointer | ||
205 | * @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd | 210 | * @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd |
206 | * @sg: SG list | 211 | * @sg: SG list |
207 | * @io_tbl: buffer descriptor (BD) table | 212 | * @io_tbl: buffer descriptor (BD) table |
208 | * @bd_tbl_dma: buffer descriptor (BD) table's dma address | 213 | * @bd_tbl_dma: buffer descriptor (BD) table's dma address |
214 | * @req: bnx2i specific command request struct | ||
209 | */ | 215 | */ |
210 | struct bnx2i_cmd { | 216 | struct bnx2i_cmd { |
211 | struct iscsi_hdr hdr; | 217 | struct iscsi_hdr hdr; |
@@ -229,6 +235,7 @@ struct bnx2i_cmd { | |||
229 | * @gen_pdu: login/nopout/logout pdu resources | 235 | * @gen_pdu: login/nopout/logout pdu resources |
230 | * @violation_notified: bit mask used to track iscsi error/warning messages | 236 | * @violation_notified: bit mask used to track iscsi error/warning messages |
231 | * already printed out | 237 | * already printed out |
238 | * @work_cnt: keeps track of the number of outstanding work | ||
232 | * | 239 | * |
233 | * iSCSI connection structure | 240 | * iSCSI connection structure |
234 | */ | 241 | */ |
@@ -252,6 +259,8 @@ struct bnx2i_conn { | |||
252 | */ | 259 | */ |
253 | struct generic_pdu_resc gen_pdu; | 260 | struct generic_pdu_resc gen_pdu; |
254 | u64 violation_notified; | 261 | u64 violation_notified; |
262 | |||
263 | atomic_t work_cnt; | ||
255 | }; | 264 | }; |
256 | 265 | ||
257 | 266 | ||
@@ -661,7 +670,6 @@ enum { | |||
661 | * @hba: adapter to which this connection belongs | 670 | * @hba: adapter to which this connection belongs |
662 | * @conn: iscsi connection this EP is linked to | 671 | * @conn: iscsi connection this EP is linked to |
663 | * @cls_ep: associated iSCSI endpoint pointer | 672 | * @cls_ep: associated iSCSI endpoint pointer |
664 | * @sess: iscsi session this EP is linked to | ||
665 | * @cm_sk: cnic sock struct | 673 | * @cm_sk: cnic sock struct |
666 | * @hba_age: age to detect if 'iscsid' issues ep_disconnect() | 674 | * @hba_age: age to detect if 'iscsid' issues ep_disconnect() |
667 | * after HBA reset is completed by bnx2i/cnic/bnx2 | 675 | * after HBA reset is completed by bnx2i/cnic/bnx2 |
@@ -687,7 +695,7 @@ struct bnx2i_endpoint { | |||
687 | u32 hba_age; | 695 | u32 hba_age; |
688 | u32 state; | 696 | u32 state; |
689 | unsigned long timestamp; | 697 | unsigned long timestamp; |
690 | int num_active_cmds; | 698 | atomic_t num_active_cmds; |
691 | u32 ec_shift; | 699 | u32 ec_shift; |
692 | 700 | ||
693 | struct qp_info qp; | 701 | struct qp_info qp; |
@@ -700,6 +708,19 @@ struct bnx2i_endpoint { | |||
700 | }; | 708 | }; |
701 | 709 | ||
702 | 710 | ||
711 | struct bnx2i_work { | ||
712 | struct list_head list; | ||
713 | struct iscsi_session *session; | ||
714 | struct bnx2i_conn *bnx2i_conn; | ||
715 | struct cqe cqe; | ||
716 | }; | ||
717 | |||
718 | struct bnx2i_percpu_s { | ||
719 | struct task_struct *iothread; | ||
720 | struct list_head work_list; | ||
721 | spinlock_t p_work_lock; | ||
722 | }; | ||
723 | |||
703 | 724 | ||
704 | /* Global variables */ | 725 | /* Global variables */ |
705 | extern unsigned int error_mask1, error_mask2; | 726 | extern unsigned int error_mask1, error_mask2; |
@@ -783,7 +804,7 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list( | |||
783 | struct bnx2i_hba *hba, u32 iscsi_cid); | 804 | struct bnx2i_hba *hba, u32 iscsi_cid); |
784 | 805 | ||
785 | extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); | 806 | extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); |
786 | extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); | 807 | extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); |
787 | 808 | ||
788 | extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); | 809 | extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); |
789 | 810 | ||
@@ -793,4 +814,8 @@ extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); | |||
793 | extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); | 814 | extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); |
794 | extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); | 815 | extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); |
795 | 816 | ||
817 | extern int bnx2i_percpu_io_thread(void *arg); | ||
818 | extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, | ||
819 | struct bnx2i_conn *bnx2i_conn, | ||
820 | struct cqe *cqe); | ||
796 | #endif | 821 | #endif |
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 372d30c099cc..030a96c646c3 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. | 1 | /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. |
2 | * | 2 | * |
3 | * Copyright (c) 2006 - 2010 Broadcom Corporation | 3 | * Copyright (c) 2006 - 2011 Broadcom Corporation |
4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. | 4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. |
5 | * Copyright (c) 2007, 2008 Mike Christie | 5 | * Copyright (c) 2007, 2008 Mike Christie |
6 | * | 6 | * |
@@ -17,6 +17,8 @@ | |||
17 | #include <scsi/libiscsi.h> | 17 | #include <scsi/libiscsi.h> |
18 | #include "bnx2i.h" | 18 | #include "bnx2i.h" |
19 | 19 | ||
20 | DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); | ||
21 | |||
20 | /** | 22 | /** |
21 | * bnx2i_get_cid_num - get cid from ep | 23 | * bnx2i_get_cid_num - get cid from ep |
22 | * @ep: endpoint pointer | 24 | * @ep: endpoint pointer |
@@ -131,16 +133,16 @@ static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code) | |||
131 | * the driver. EQ event is generated CQ index is hit or at least 1 CQ is | 133 | * the driver. EQ event is generated CQ index is hit or at least 1 CQ is |
132 | * outstanding and on chip timer expires | 134 | * outstanding and on chip timer expires |
133 | */ | 135 | */ |
134 | void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) | 136 | int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) |
135 | { | 137 | { |
136 | struct bnx2i_5771x_cq_db *cq_db; | 138 | struct bnx2i_5771x_cq_db *cq_db; |
137 | u16 cq_index; | 139 | u16 cq_index; |
138 | u16 next_index; | 140 | u16 next_index = 0; |
139 | u32 num_active_cmds; | 141 | u32 num_active_cmds; |
140 | 142 | ||
141 | /* Coalesce CQ entries only on 10G devices */ | 143 | /* Coalesce CQ entries only on 10G devices */ |
142 | if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) | 144 | if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) |
143 | return; | 145 | return 0; |
144 | 146 | ||
145 | /* Do not update CQ DB multiple times before firmware writes | 147 | /* Do not update CQ DB multiple times before firmware writes |
146 | * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious | 148 | * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious |
@@ -150,16 +152,17 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) | |||
150 | 152 | ||
151 | if (action != CNIC_ARM_CQE_FP) | 153 | if (action != CNIC_ARM_CQE_FP) |
152 | if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF) | 154 | if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF) |
153 | return; | 155 | return 0; |
154 | 156 | ||
155 | if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) { | 157 | if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) { |
156 | num_active_cmds = ep->num_active_cmds; | 158 | num_active_cmds = atomic_read(&ep->num_active_cmds); |
157 | if (num_active_cmds <= event_coal_min) | 159 | if (num_active_cmds <= event_coal_min) |
158 | next_index = 1; | 160 | next_index = 1; |
159 | else | 161 | else { |
160 | next_index = event_coal_min + | 162 | next_index = num_active_cmds >> ep->ec_shift; |
161 | ((num_active_cmds - event_coal_min) >> | 163 | if (next_index > num_active_cmds - event_coal_min) |
162 | ep->ec_shift); | 164 | next_index = num_active_cmds - event_coal_min; |
165 | } | ||
163 | if (!next_index) | 166 | if (!next_index) |
164 | next_index = 1; | 167 | next_index = 1; |
165 | cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1; | 168 | cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1; |
@@ -170,6 +173,7 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) | |||
170 | 173 | ||
171 | cq_db->sqn[0] = cq_index; | 174 | cq_db->sqn[0] = cq_index; |
172 | } | 175 | } |
176 | return next_index; | ||
173 | } | 177 | } |
174 | 178 | ||
175 | 179 | ||
@@ -265,7 +269,7 @@ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) | |||
265 | struct bnx2i_5771x_sq_rq_db *sq_db; | 269 | struct bnx2i_5771x_sq_rq_db *sq_db; |
266 | struct bnx2i_endpoint *ep = bnx2i_conn->ep; | 270 | struct bnx2i_endpoint *ep = bnx2i_conn->ep; |
267 | 271 | ||
268 | ep->num_active_cmds++; | 272 | atomic_inc(&ep->num_active_cmds); |
269 | wmb(); /* flush SQ WQE memory before the doorbell is rung */ | 273 | wmb(); /* flush SQ WQE memory before the doorbell is rung */ |
270 | if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { | 274 | if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { |
271 | sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt; | 275 | sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt; |
@@ -430,7 +434,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, | |||
430 | default: | 434 | default: |
431 | tmfabort_wqe->ref_itt = RESERVED_ITT; | 435 | tmfabort_wqe->ref_itt = RESERVED_ITT; |
432 | } | 436 | } |
433 | memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun)); | 437 | memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun)); |
434 | tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); | 438 | tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); |
435 | tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); | 439 | tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); |
436 | 440 | ||
@@ -547,7 +551,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, | |||
547 | 551 | ||
548 | nopout_wqe->op_code = nopout_hdr->opcode; | 552 | nopout_wqe->op_code = nopout_hdr->opcode; |
549 | nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL; | 553 | nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL; |
550 | memcpy(nopout_wqe->lun, nopout_hdr->lun, 8); | 554 | memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8); |
551 | 555 | ||
552 | if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { | 556 | if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { |
553 | u32 tmp = nopout_wqe->lun[0]; | 557 | u32 tmp = nopout_wqe->lun[0]; |
@@ -1331,14 +1335,15 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) | |||
1331 | 1335 | ||
1332 | /** | 1336 | /** |
1333 | * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. | 1337 | * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. |
1334 | * @conn: iscsi connection | 1338 | * @session: iscsi session |
1339 | * @bnx2i_conn: bnx2i connection | ||
1335 | * @cqe: pointer to newly DMA'ed CQE entry for processing | 1340 | * @cqe: pointer to newly DMA'ed CQE entry for processing |
1336 | * | 1341 | * |
1337 | * process SCSI CMD Response CQE & complete the request to SCSI-ML | 1342 | * process SCSI CMD Response CQE & complete the request to SCSI-ML |
1338 | */ | 1343 | */ |
1339 | static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, | 1344 | int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, |
1340 | struct bnx2i_conn *bnx2i_conn, | 1345 | struct bnx2i_conn *bnx2i_conn, |
1341 | struct cqe *cqe) | 1346 | struct cqe *cqe) |
1342 | { | 1347 | { |
1343 | struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; | 1348 | struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; |
1344 | struct bnx2i_cmd_response *resp_cqe; | 1349 | struct bnx2i_cmd_response *resp_cqe; |
@@ -1348,7 +1353,7 @@ static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, | |||
1348 | u32 datalen = 0; | 1353 | u32 datalen = 0; |
1349 | 1354 | ||
1350 | resp_cqe = (struct bnx2i_cmd_response *)cqe; | 1355 | resp_cqe = (struct bnx2i_cmd_response *)cqe; |
1351 | spin_lock(&session->lock); | 1356 | spin_lock_bh(&session->lock); |
1352 | task = iscsi_itt_to_task(conn, | 1357 | task = iscsi_itt_to_task(conn, |
1353 | resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); | 1358 | resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); |
1354 | if (!task) | 1359 | if (!task) |
@@ -1409,7 +1414,7 @@ done: | |||
1409 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, | 1414 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, |
1410 | conn->data, datalen); | 1415 | conn->data, datalen); |
1411 | fail: | 1416 | fail: |
1412 | spin_unlock(&session->lock); | 1417 | spin_unlock_bh(&session->lock); |
1413 | return 0; | 1418 | return 0; |
1414 | } | 1419 | } |
1415 | 1420 | ||
@@ -1711,7 +1716,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session, | |||
1711 | hdr->flags = ISCSI_FLAG_CMD_FINAL; | 1716 | hdr->flags = ISCSI_FLAG_CMD_FINAL; |
1712 | hdr->itt = task->hdr->itt; | 1717 | hdr->itt = task->hdr->itt; |
1713 | hdr->ttt = cpu_to_be32(nop_in->ttt); | 1718 | hdr->ttt = cpu_to_be32(nop_in->ttt); |
1714 | memcpy(hdr->lun, nop_in->lun, 8); | 1719 | memcpy(&hdr->lun, nop_in->lun, 8); |
1715 | } | 1720 | } |
1716 | done: | 1721 | done: |
1717 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); | 1722 | __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); |
@@ -1754,7 +1759,7 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session, | |||
1754 | resp_hdr->opcode = async_cqe->op_code; | 1759 | resp_hdr->opcode = async_cqe->op_code; |
1755 | resp_hdr->flags = 0x80; | 1760 | resp_hdr->flags = 0x80; |
1756 | 1761 | ||
1757 | memcpy(resp_hdr->lun, async_cqe->lun, 8); | 1762 | memcpy(&resp_hdr->lun, async_cqe->lun, 8); |
1758 | resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn); | 1763 | resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn); |
1759 | resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn); | 1764 | resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn); |
1760 | 1765 | ||
@@ -1836,21 +1841,136 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, | |||
1836 | } | 1841 | } |
1837 | 1842 | ||
1838 | 1843 | ||
1844 | /** | ||
1845 | * bnx2i_percpu_io_thread - thread per cpu for ios | ||
1846 | * | ||
1847 | * @arg: ptr to bnx2i_percpu_info structure | ||
1848 | */ | ||
1849 | int bnx2i_percpu_io_thread(void *arg) | ||
1850 | { | ||
1851 | struct bnx2i_percpu_s *p = arg; | ||
1852 | struct bnx2i_work *work, *tmp; | ||
1853 | LIST_HEAD(work_list); | ||
1854 | |||
1855 | set_user_nice(current, -20); | ||
1856 | |||
1857 | while (!kthread_should_stop()) { | ||
1858 | spin_lock_bh(&p->p_work_lock); | ||
1859 | while (!list_empty(&p->work_list)) { | ||
1860 | list_splice_init(&p->work_list, &work_list); | ||
1861 | spin_unlock_bh(&p->p_work_lock); | ||
1862 | |||
1863 | list_for_each_entry_safe(work, tmp, &work_list, list) { | ||
1864 | list_del_init(&work->list); | ||
1865 | /* work allocated in the bh, freed here */ | ||
1866 | bnx2i_process_scsi_cmd_resp(work->session, | ||
1867 | work->bnx2i_conn, | ||
1868 | &work->cqe); | ||
1869 | atomic_dec(&work->bnx2i_conn->work_cnt); | ||
1870 | kfree(work); | ||
1871 | } | ||
1872 | spin_lock_bh(&p->p_work_lock); | ||
1873 | } | ||
1874 | set_current_state(TASK_INTERRUPTIBLE); | ||
1875 | spin_unlock_bh(&p->p_work_lock); | ||
1876 | schedule(); | ||
1877 | } | ||
1878 | __set_current_state(TASK_RUNNING); | ||
1879 | |||
1880 | return 0; | ||
1881 | } | ||
1882 | |||
1883 | |||
1884 | /** | ||
1885 | * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread | ||
1886 | * @bnx2i_conn: bnx2i connection | ||
1887 | * | ||
1888 | * this function is called by generic KCQ handler to queue all pending cmd | ||
1889 | * completion CQEs | ||
1890 | * | ||
1891 | * The implementation is to queue the cmd response based on the | ||
1892 | * last recorded command for the given connection. The | ||
1893 | * cpu_id gets recorded upon task_xmit. No out-of-order completion! | ||
1894 | */ | ||
1895 | static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, | ||
1896 | struct bnx2i_conn *bnx2i_conn, | ||
1897 | struct bnx2i_nop_in_msg *cqe) | ||
1898 | { | ||
1899 | struct bnx2i_work *bnx2i_work = NULL; | ||
1900 | struct bnx2i_percpu_s *p = NULL; | ||
1901 | struct iscsi_task *task; | ||
1902 | struct scsi_cmnd *sc; | ||
1903 | int rc = 0; | ||
1904 | int cpu; | ||
1905 | |||
1906 | spin_lock(&session->lock); | ||
1907 | task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, | ||
1908 | cqe->itt & ISCSI_CMD_RESPONSE_INDEX); | ||
1909 | if (!task) { | ||
1910 | spin_unlock(&session->lock); | ||
1911 | return -EINVAL; | ||
1912 | } | ||
1913 | sc = task->sc; | ||
1914 | spin_unlock(&session->lock); | ||
1915 | |||
1916 | if (!blk_rq_cpu_valid(sc->request)) | ||
1917 | cpu = smp_processor_id(); | ||
1918 | else | ||
1919 | cpu = sc->request->cpu; | ||
1920 | |||
1921 | p = &per_cpu(bnx2i_percpu, cpu); | ||
1922 | spin_lock(&p->p_work_lock); | ||
1923 | if (unlikely(!p->iothread)) { | ||
1924 | rc = -EINVAL; | ||
1925 | goto err; | ||
1926 | } | ||
1927 | /* Alloc and copy to the cqe */ | ||
1928 | bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC); | ||
1929 | if (bnx2i_work) { | ||
1930 | INIT_LIST_HEAD(&bnx2i_work->list); | ||
1931 | bnx2i_work->session = session; | ||
1932 | bnx2i_work->bnx2i_conn = bnx2i_conn; | ||
1933 | memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe)); | ||
1934 | list_add_tail(&bnx2i_work->list, &p->work_list); | ||
1935 | atomic_inc(&bnx2i_conn->work_cnt); | ||
1936 | wake_up_process(p->iothread); | ||
1937 | spin_unlock(&p->p_work_lock); | ||
1938 | goto done; | ||
1939 | } else | ||
1940 | rc = -ENOMEM; | ||
1941 | err: | ||
1942 | spin_unlock(&p->p_work_lock); | ||
1943 | bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe); | ||
1944 | done: | ||
1945 | return rc; | ||
1946 | } | ||
1947 | |||
1839 | 1948 | ||
1840 | /** | 1949 | /** |
1841 | * bnx2i_process_new_cqes - process newly DMA'ed CQE's | 1950 | * bnx2i_process_new_cqes - process newly DMA'ed CQE's |
1842 | * @bnx2i_conn: iscsi connection | 1951 | * @bnx2i_conn: bnx2i connection |
1843 | * | 1952 | * |
1844 | * this function is called by generic KCQ handler to process all pending CQE's | 1953 | * this function is called by generic KCQ handler to process all pending CQE's |
1845 | */ | 1954 | */ |
1846 | static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) | 1955 | static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) |
1847 | { | 1956 | { |
1848 | struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; | 1957 | struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; |
1849 | struct iscsi_session *session = conn->session; | 1958 | struct iscsi_session *session = conn->session; |
1850 | struct qp_info *qp = &bnx2i_conn->ep->qp; | 1959 | struct qp_info *qp; |
1851 | struct bnx2i_nop_in_msg *nopin; | 1960 | struct bnx2i_nop_in_msg *nopin; |
1852 | int tgt_async_msg; | 1961 | int tgt_async_msg; |
1962 | int cqe_cnt = 0; | ||
1853 | 1963 | ||
1964 | if (bnx2i_conn->ep == NULL) | ||
1965 | return 0; | ||
1966 | |||
1967 | qp = &bnx2i_conn->ep->qp; | ||
1968 | |||
1969 | if (!qp->cq_virt) { | ||
1970 | printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!", | ||
1971 | bnx2i_conn->hba->netdev->name); | ||
1972 | goto out; | ||
1973 | } | ||
1854 | while (1) { | 1974 | while (1) { |
1855 | nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; | 1975 | nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; |
1856 | if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) | 1976 | if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) |
@@ -1873,8 +1993,9 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) | |||
1873 | switch (nopin->op_code) { | 1993 | switch (nopin->op_code) { |
1874 | case ISCSI_OP_SCSI_CMD_RSP: | 1994 | case ISCSI_OP_SCSI_CMD_RSP: |
1875 | case ISCSI_OP_SCSI_DATA_IN: | 1995 | case ISCSI_OP_SCSI_DATA_IN: |
1876 | bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, | 1996 | /* Run the kthread engine only for data cmds |
1877 | qp->cq_cons_qe); | 1997 | All other cmds will be completed in this bh! */ |
1998 | bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin); | ||
1878 | break; | 1999 | break; |
1879 | case ISCSI_OP_LOGIN_RSP: | 2000 | case ISCSI_OP_LOGIN_RSP: |
1880 | bnx2i_process_login_resp(session, bnx2i_conn, | 2001 | bnx2i_process_login_resp(session, bnx2i_conn, |
@@ -1918,13 +2039,21 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) | |||
1918 | printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", | 2039 | printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", |
1919 | nopin->op_code); | 2040 | nopin->op_code); |
1920 | } | 2041 | } |
1921 | if (!tgt_async_msg) | 2042 | if (!tgt_async_msg) { |
1922 | bnx2i_conn->ep->num_active_cmds--; | 2043 | if (!atomic_read(&bnx2i_conn->ep->num_active_cmds)) |
2044 | printk(KERN_ALERT "bnx2i (%s): no active cmd! " | ||
2045 | "op 0x%x\n", | ||
2046 | bnx2i_conn->hba->netdev->name, | ||
2047 | nopin->op_code); | ||
2048 | else | ||
2049 | atomic_dec(&bnx2i_conn->ep->num_active_cmds); | ||
2050 | } | ||
1923 | cqe_out: | 2051 | cqe_out: |
1924 | /* clear out in production version only, till beta keep opcode | 2052 | /* clear out in production version only, till beta keep opcode |
1925 | * field intact, will be helpful in debugging (context dump) | 2053 | * field intact, will be helpful in debugging (context dump) |
1926 | * nopin->op_code = 0; | 2054 | * nopin->op_code = 0; |
1927 | */ | 2055 | */ |
2056 | cqe_cnt++; | ||
1928 | qp->cqe_exp_seq_sn++; | 2057 | qp->cqe_exp_seq_sn++; |
1929 | if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) | 2058 | if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) |
1930 | qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; | 2059 | qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; |
@@ -1937,6 +2066,8 @@ cqe_out: | |||
1937 | qp->cq_cons_idx++; | 2066 | qp->cq_cons_idx++; |
1938 | } | 2067 | } |
1939 | } | 2068 | } |
2069 | out: | ||
2070 | return cqe_cnt; | ||
1940 | } | 2071 | } |
1941 | 2072 | ||
1942 | /** | 2073 | /** |
@@ -1952,6 +2083,7 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, | |||
1952 | { | 2083 | { |
1953 | struct bnx2i_conn *bnx2i_conn; | 2084 | struct bnx2i_conn *bnx2i_conn; |
1954 | u32 iscsi_cid; | 2085 | u32 iscsi_cid; |
2086 | int nxt_idx; | ||
1955 | 2087 | ||
1956 | iscsi_cid = new_cqe_kcqe->iscsi_conn_id; | 2088 | iscsi_cid = new_cqe_kcqe->iscsi_conn_id; |
1957 | bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); | 2089 | bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); |
@@ -1964,9 +2096,12 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, | |||
1964 | printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); | 2096 | printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); |
1965 | return; | 2097 | return; |
1966 | } | 2098 | } |
2099 | |||
1967 | bnx2i_process_new_cqes(bnx2i_conn); | 2100 | bnx2i_process_new_cqes(bnx2i_conn); |
1968 | bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); | 2101 | nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, |
1969 | bnx2i_process_new_cqes(bnx2i_conn); | 2102 | CNIC_ARM_CQE_FP); |
2103 | if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn)) | ||
2104 | bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); | ||
1970 | } | 2105 | } |
1971 | 2106 | ||
1972 | 2107 | ||
@@ -2312,7 +2447,7 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, | |||
2312 | printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " | 2447 | printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " |
2313 | "opcode\n", hba->netdev->name); | 2448 | "opcode\n", hba->netdev->name); |
2314 | else if (ofld_kcqe->completion_status == | 2449 | else if (ofld_kcqe->completion_status == |
2315 | ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) | 2450 | ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) |
2316 | /* error status code valid only for 5771x chipset */ | 2451 | /* error status code valid only for 5771x chipset */ |
2317 | ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; | 2452 | ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; |
2318 | else | 2453 | else |
@@ -2517,7 +2652,7 @@ static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) | |||
2517 | 2652 | ||
2518 | 2653 | ||
2519 | static int bnx2i_send_nl_mesg(void *context, u32 msg_type, | 2654 | static int bnx2i_send_nl_mesg(void *context, u32 msg_type, |
2520 | char *buf, u16 buflen) | 2655 | char *buf, u16 buflen) |
2521 | { | 2656 | { |
2522 | struct bnx2i_hba *hba = context; | 2657 | struct bnx2i_hba *hba = context; |
2523 | int rc; | 2658 | int rc; |
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 6973413e91ec..1a947f1b9729 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. | 1 | /* bnx2i.c: Broadcom NetXtreme II iSCSI driver. |
2 | * | 2 | * |
3 | * Copyright (c) 2006 - 2010 Broadcom Corporation | 3 | * Copyright (c) 2006 - 2011 Broadcom Corporation |
4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. | 4 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. |
5 | * Copyright (c) 2007, 2008 Mike Christie | 5 | * Copyright (c) 2007, 2008 Mike Christie |
6 | * | 6 | * |
@@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); | |||
18 | static u32 adapter_count; | 18 | static u32 adapter_count; |
19 | 19 | ||
20 | #define DRV_MODULE_NAME "bnx2i" | 20 | #define DRV_MODULE_NAME "bnx2i" |
21 | #define DRV_MODULE_VERSION "2.6.2.3" | 21 | #define DRV_MODULE_VERSION "2.7.0.3" |
22 | #define DRV_MODULE_RELDATE "Dec 31, 2010" | 22 | #define DRV_MODULE_RELDATE "Jun 15, 2011" |
23 | 23 | ||
24 | static char version[] __devinitdata = | 24 | static char version[] __devinitdata = |
25 | "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ | 25 | "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ |
@@ -40,7 +40,7 @@ unsigned int event_coal_min = 24; | |||
40 | module_param(event_coal_min, int, 0664); | 40 | module_param(event_coal_min, int, 0664); |
41 | MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands"); | 41 | MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands"); |
42 | 42 | ||
43 | unsigned int event_coal_div = 1; | 43 | unsigned int event_coal_div = 2; |
44 | module_param(event_coal_div, int, 0664); | 44 | module_param(event_coal_div, int, 0664); |
45 | MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); | 45 | MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); |
46 | 46 | ||
@@ -66,6 +66,15 @@ MODULE_PARM_DESC(rq_size, "Configure RQ size"); | |||
66 | 66 | ||
67 | u64 iscsi_error_mask = 0x00; | 67 | u64 iscsi_error_mask = 0x00; |
68 | 68 | ||
69 | DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); | ||
70 | |||
71 | static int bnx2i_cpu_callback(struct notifier_block *nfb, | ||
72 | unsigned long action, void *hcpu); | ||
73 | /* notification function for CPU hotplug events */ | ||
74 | static struct notifier_block bnx2i_cpu_notifier = { | ||
75 | .notifier_call = bnx2i_cpu_callback, | ||
76 | }; | ||
77 | |||
69 | 78 | ||
70 | /** | 79 | /** |
71 | * bnx2i_identify_device - identifies NetXtreme II device type | 80 | * bnx2i_identify_device - identifies NetXtreme II device type |
@@ -172,21 +181,14 @@ void bnx2i_start(void *handle) | |||
172 | struct bnx2i_hba *hba = handle; | 181 | struct bnx2i_hba *hba = handle; |
173 | int i = HZ; | 182 | int i = HZ; |
174 | 183 | ||
175 | if (!hba->cnic->max_iscsi_conn) { | 184 | /* |
176 | printk(KERN_ALERT "bnx2i: dev %s does not support " | 185 | * We should never register devices that don't support iSCSI |
177 | "iSCSI\n", hba->netdev->name); | 186 | * (see bnx2i_init_one), so something is wrong if we try to |
187 | * start a iSCSI adapter on hardware with 0 supported iSCSI | ||
188 | * connections | ||
189 | */ | ||
190 | BUG_ON(!hba->cnic->max_iscsi_conn); | ||
178 | 191 | ||
179 | if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { | ||
180 | mutex_lock(&bnx2i_dev_lock); | ||
181 | list_del_init(&hba->link); | ||
182 | adapter_count--; | ||
183 | hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); | ||
184 | clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); | ||
185 | mutex_unlock(&bnx2i_dev_lock); | ||
186 | bnx2i_free_hba(hba); | ||
187 | } | ||
188 | return; | ||
189 | } | ||
190 | bnx2i_send_fw_iscsi_init_msg(hba); | 192 | bnx2i_send_fw_iscsi_init_msg(hba); |
191 | while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) | 193 | while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) |
192 | msleep(BNX2I_INIT_POLL_TIME); | 194 | msleep(BNX2I_INIT_POLL_TIME); |
@@ -290,6 +292,13 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) | |||
290 | int rc; | 292 | int rc; |
291 | 293 | ||
292 | mutex_lock(&bnx2i_dev_lock); | 294 | mutex_lock(&bnx2i_dev_lock); |
295 | if (!cnic->max_iscsi_conn) { | ||
296 | printk(KERN_ALERT "bnx2i: dev %s does not support " | ||
297 | "iSCSI\n", hba->netdev->name); | ||
298 | rc = -EOPNOTSUPP; | ||
299 | goto out; | ||
300 | } | ||
301 | |||
293 | hba->cnic = cnic; | 302 | hba->cnic = cnic; |
294 | rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); | 303 | rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); |
295 | if (!rc) { | 304 | if (!rc) { |
@@ -307,6 +316,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) | |||
307 | else | 316 | else |
308 | printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); | 317 | printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); |
309 | 318 | ||
319 | out: | ||
310 | mutex_unlock(&bnx2i_dev_lock); | 320 | mutex_unlock(&bnx2i_dev_lock); |
311 | 321 | ||
312 | return rc; | 322 | return rc; |
@@ -371,6 +381,91 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) | |||
371 | 381 | ||
372 | 382 | ||
373 | /** | 383 | /** |
384 | * bnx2i_percpu_thread_create - Create a receive thread for an | ||
385 | * online CPU | ||
386 | * | ||
387 | * @cpu: cpu index for the online cpu | ||
388 | */ | ||
389 | static void bnx2i_percpu_thread_create(unsigned int cpu) | ||
390 | { | ||
391 | struct bnx2i_percpu_s *p; | ||
392 | struct task_struct *thread; | ||
393 | |||
394 | p = &per_cpu(bnx2i_percpu, cpu); | ||
395 | |||
396 | thread = kthread_create(bnx2i_percpu_io_thread, (void *)p, | ||
397 | "bnx2i_thread/%d", cpu); | ||
398 | /* bind thread to the cpu */ | ||
399 | if (likely(!IS_ERR(thread))) { | ||
400 | kthread_bind(thread, cpu); | ||
401 | p->iothread = thread; | ||
402 | wake_up_process(thread); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | |||
407 | static void bnx2i_percpu_thread_destroy(unsigned int cpu) | ||
408 | { | ||
409 | struct bnx2i_percpu_s *p; | ||
410 | struct task_struct *thread; | ||
411 | struct bnx2i_work *work, *tmp; | ||
412 | |||
413 | /* Prevent any new work from being queued for this CPU */ | ||
414 | p = &per_cpu(bnx2i_percpu, cpu); | ||
415 | spin_lock_bh(&p->p_work_lock); | ||
416 | thread = p->iothread; | ||
417 | p->iothread = NULL; | ||
418 | |||
419 | /* Free all work in the list */ | ||
420 | list_for_each_entry_safe(work, tmp, &p->work_list, list) { | ||
421 | list_del_init(&work->list); | ||
422 | bnx2i_process_scsi_cmd_resp(work->session, | ||
423 | work->bnx2i_conn, &work->cqe); | ||
424 | kfree(work); | ||
425 | } | ||
426 | |||
427 | spin_unlock_bh(&p->p_work_lock); | ||
428 | if (thread) | ||
429 | kthread_stop(thread); | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * bnx2i_cpu_callback - Handler for CPU hotplug events | ||
435 | * | ||
436 | * @nfb: The callback data block | ||
437 | * @action: The event triggering the callback | ||
438 | * @hcpu: The index of the CPU that the event is for | ||
439 | * | ||
440 | * This creates or destroys per-CPU data for iSCSI | ||
441 | * | ||
442 | * Returns NOTIFY_OK always. | ||
443 | */ | ||
444 | static int bnx2i_cpu_callback(struct notifier_block *nfb, | ||
445 | unsigned long action, void *hcpu) | ||
446 | { | ||
447 | unsigned cpu = (unsigned long)hcpu; | ||
448 | |||
449 | switch (action) { | ||
450 | case CPU_ONLINE: | ||
451 | case CPU_ONLINE_FROZEN: | ||
452 | printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n", | ||
453 | cpu); | ||
454 | bnx2i_percpu_thread_create(cpu); | ||
455 | break; | ||
456 | case CPU_DEAD: | ||
457 | case CPU_DEAD_FROZEN: | ||
458 | printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu); | ||
459 | bnx2i_percpu_thread_destroy(cpu); | ||
460 | break; | ||
461 | default: | ||
462 | break; | ||
463 | } | ||
464 | return NOTIFY_OK; | ||
465 | } | ||
466 | |||
467 | |||
468 | /** | ||
374 | * bnx2i_mod_init - module init entry point | 469 | * bnx2i_mod_init - module init entry point |
375 | * | 470 | * |
376 | * initialize any driver wide global data structures such as endpoint pool, | 471 | * initialize any driver wide global data structures such as endpoint pool, |
@@ -380,6 +475,8 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) | |||
380 | static int __init bnx2i_mod_init(void) | 475 | static int __init bnx2i_mod_init(void) |
381 | { | 476 | { |
382 | int err; | 477 | int err; |
478 | unsigned cpu = 0; | ||
479 | struct bnx2i_percpu_s *p; | ||
383 | 480 | ||
384 | printk(KERN_INFO "%s", version); | 481 | printk(KERN_INFO "%s", version); |
385 | 482 | ||
@@ -402,6 +499,20 @@ static int __init bnx2i_mod_init(void) | |||
402 | goto unreg_xport; | 499 | goto unreg_xport; |
403 | } | 500 | } |
404 | 501 | ||
502 | /* Create percpu kernel threads to handle iSCSI I/O completions */ | ||
503 | for_each_possible_cpu(cpu) { | ||
504 | p = &per_cpu(bnx2i_percpu, cpu); | ||
505 | INIT_LIST_HEAD(&p->work_list); | ||
506 | spin_lock_init(&p->p_work_lock); | ||
507 | p->iothread = NULL; | ||
508 | } | ||
509 | |||
510 | for_each_online_cpu(cpu) | ||
511 | bnx2i_percpu_thread_create(cpu); | ||
512 | |||
513 | /* Initialize per CPU interrupt thread */ | ||
514 | register_hotcpu_notifier(&bnx2i_cpu_notifier); | ||
515 | |||
405 | return 0; | 516 | return 0; |
406 | 517 | ||
407 | unreg_xport: | 518 | unreg_xport: |
@@ -422,6 +533,7 @@ out: | |||
422 | static void __exit bnx2i_mod_exit(void) | 533 | static void __exit bnx2i_mod_exit(void) |
423 | { | 534 | { |
424 | struct bnx2i_hba *hba; | 535 | struct bnx2i_hba *hba; |
536 | unsigned cpu = 0; | ||
425 | 537 | ||
426 | mutex_lock(&bnx2i_dev_lock); | 538 | mutex_lock(&bnx2i_dev_lock); |
427 | while (!list_empty(&adapter_list)) { | 539 | while (!list_empty(&adapter_list)) { |
@@ -439,6 +551,11 @@ static void __exit bnx2i_mod_exit(void) | |||
439 | } | 551 | } |
440 | mutex_unlock(&bnx2i_dev_lock); | 552 | mutex_unlock(&bnx2i_dev_lock); |
441 | 553 | ||
554 | unregister_hotcpu_notifier(&bnx2i_cpu_notifier); | ||
555 | |||
556 | for_each_online_cpu(cpu) | ||
557 | bnx2i_percpu_thread_destroy(cpu); | ||
558 | |||
442 | iscsi_unregister_transport(&bnx2i_iscsi_transport); | 559 | iscsi_unregister_transport(&bnx2i_iscsi_transport); |
443 | cnic_unregister_driver(CNIC_ULP_ISCSI); | 560 | cnic_unregister_driver(CNIC_ULP_ISCSI); |
444 | } | 561 | } |
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 041928b23cb0..5c55a75ae597 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. | 2 | * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. |
3 | * | 3 | * |
4 | * Copyright (c) 2006 - 2010 Broadcom Corporation | 4 | * Copyright (c) 2006 - 2011 Broadcom Corporation |
5 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. | 5 | * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. |
6 | * Copyright (c) 2007, 2008 Mike Christie | 6 | * Copyright (c) 2007, 2008 Mike Christie |
7 | * | 7 | * |
@@ -27,6 +27,7 @@ static struct scsi_host_template bnx2i_host_template; | |||
27 | */ | 27 | */ |
28 | static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ | 28 | static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ |
29 | 29 | ||
30 | DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); | ||
30 | 31 | ||
31 | static int bnx2i_adapter_ready(struct bnx2i_hba *hba) | 32 | static int bnx2i_adapter_ready(struct bnx2i_hba *hba) |
32 | { | 33 | { |
@@ -1214,7 +1215,8 @@ static int bnx2i_task_xmit(struct iscsi_task *task) | |||
1214 | struct bnx2i_cmd *cmd = task->dd_data; | 1215 | struct bnx2i_cmd *cmd = task->dd_data; |
1215 | struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; | 1216 | struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; |
1216 | 1217 | ||
1217 | if (bnx2i_conn->ep->num_active_cmds + 1 > hba->max_sqes) | 1218 | if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1 > |
1219 | hba->max_sqes) | ||
1218 | return -ENOMEM; | 1220 | return -ENOMEM; |
1219 | 1221 | ||
1220 | /* | 1222 | /* |
@@ -1354,6 +1356,9 @@ bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) | |||
1354 | bnx2i_conn = conn->dd_data; | 1356 | bnx2i_conn = conn->dd_data; |
1355 | bnx2i_conn->cls_conn = cls_conn; | 1357 | bnx2i_conn->cls_conn = cls_conn; |
1356 | bnx2i_conn->hba = hba; | 1358 | bnx2i_conn->hba = hba; |
1359 | |||
1360 | atomic_set(&bnx2i_conn->work_cnt, 0); | ||
1361 | |||
1357 | /* 'ep' ptr will be assigned in bind() call */ | 1362 | /* 'ep' ptr will be assigned in bind() call */ |
1358 | bnx2i_conn->ep = NULL; | 1363 | bnx2i_conn->ep = NULL; |
1359 | init_completion(&bnx2i_conn->cmd_cleanup_cmpl); | 1364 | init_completion(&bnx2i_conn->cmd_cleanup_cmpl); |
@@ -1457,11 +1462,34 @@ static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn) | |||
1457 | struct bnx2i_conn *bnx2i_conn = conn->dd_data; | 1462 | struct bnx2i_conn *bnx2i_conn = conn->dd_data; |
1458 | struct Scsi_Host *shost; | 1463 | struct Scsi_Host *shost; |
1459 | struct bnx2i_hba *hba; | 1464 | struct bnx2i_hba *hba; |
1465 | struct bnx2i_work *work, *tmp; | ||
1466 | unsigned cpu = 0; | ||
1467 | struct bnx2i_percpu_s *p; | ||
1460 | 1468 | ||
1461 | shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); | 1469 | shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); |
1462 | hba = iscsi_host_priv(shost); | 1470 | hba = iscsi_host_priv(shost); |
1463 | 1471 | ||
1464 | bnx2i_conn_free_login_resources(hba, bnx2i_conn); | 1472 | bnx2i_conn_free_login_resources(hba, bnx2i_conn); |
1473 | |||
1474 | if (atomic_read(&bnx2i_conn->work_cnt)) { | ||
1475 | for_each_online_cpu(cpu) { | ||
1476 | p = &per_cpu(bnx2i_percpu, cpu); | ||
1477 | spin_lock_bh(&p->p_work_lock); | ||
1478 | list_for_each_entry_safe(work, tmp, | ||
1479 | &p->work_list, list) { | ||
1480 | if (work->session == conn->session && | ||
1481 | work->bnx2i_conn == bnx2i_conn) { | ||
1482 | list_del_init(&work->list); | ||
1483 | kfree(work); | ||
1484 | if (!atomic_dec_and_test( | ||
1485 | &bnx2i_conn->work_cnt)) | ||
1486 | break; | ||
1487 | } | ||
1488 | } | ||
1489 | spin_unlock_bh(&p->p_work_lock); | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1465 | iscsi_conn_teardown(cls_conn); | 1493 | iscsi_conn_teardown(cls_conn); |
1466 | } | 1494 | } |
1467 | 1495 | ||
@@ -1769,7 +1797,7 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, | |||
1769 | } | 1797 | } |
1770 | bnx2i_ep = ep->dd_data; | 1798 | bnx2i_ep = ep->dd_data; |
1771 | 1799 | ||
1772 | bnx2i_ep->num_active_cmds = 0; | 1800 | atomic_set(&bnx2i_ep->num_active_cmds, 0); |
1773 | iscsi_cid = bnx2i_alloc_iscsi_cid(hba); | 1801 | iscsi_cid = bnx2i_alloc_iscsi_cid(hba); |
1774 | if (iscsi_cid == -1) { | 1802 | if (iscsi_cid == -1) { |
1775 | printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " | 1803 | printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " |
@@ -2163,9 +2191,9 @@ static struct scsi_host_template bnx2i_host_template = { | |||
2163 | .eh_device_reset_handler = iscsi_eh_device_reset, | 2191 | .eh_device_reset_handler = iscsi_eh_device_reset, |
2164 | .eh_target_reset_handler = iscsi_eh_recover_target, | 2192 | .eh_target_reset_handler = iscsi_eh_recover_target, |
2165 | .change_queue_depth = iscsi_change_queue_depth, | 2193 | .change_queue_depth = iscsi_change_queue_depth, |
2166 | .can_queue = 1024, | 2194 | .can_queue = 2048, |
2167 | .max_sectors = 127, | 2195 | .max_sectors = 127, |
2168 | .cmd_per_lun = 24, | 2196 | .cmd_per_lun = 128, |
2169 | .this_id = -1, | 2197 | .this_id = -1, |
2170 | .use_clustering = ENABLE_CLUSTERING, | 2198 | .use_clustering = ENABLE_CLUSTERING, |
2171 | .sg_tablesize = ISCSI_MAX_BDS_PER_CMD, | 2199 | .sg_tablesize = ISCSI_MAX_BDS_PER_CMD, |
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c index 9174196d9033..83a77f7244d2 100644 --- a/drivers/scsi/bnx2i/bnx2i_sysfs.c +++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. | 1 | /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. |
2 | * | 2 | * |
3 | * Copyright (c) 2004 - 2010 Broadcom Corporation | 3 | * Copyright (c) 2004 - 2011 Broadcom Corporation |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |