diff options
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i.h | 31 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_hwi.c | 183 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_init.c | 118 | ||||
-rw-r--r-- | drivers/scsi/bnx2i/bnx2i_iscsi.c | 36 |
4 files changed, 333 insertions, 35 deletions
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index 6bdd25a93db9..239bc4e395b2 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h | |||
@@ -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 550e6c4ea8b4..a501a72a243d 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c | |||
@@ -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; |
@@ -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 | ||
@@ -1836,21 +1841,130 @@ 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 | |||
1905 | spin_lock(&session->lock); | ||
1906 | task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, | ||
1907 | cqe->itt & ISCSI_CMD_RESPONSE_INDEX); | ||
1908 | if (!task) { | ||
1909 | spin_unlock(&session->lock); | ||
1910 | return -EINVAL; | ||
1911 | } | ||
1912 | sc = task->sc; | ||
1913 | spin_unlock(&session->lock); | ||
1914 | |||
1915 | p = &per_cpu(bnx2i_percpu, sc->request->cpu); | ||
1916 | spin_lock(&p->p_work_lock); | ||
1917 | if (unlikely(!p->iothread)) { | ||
1918 | rc = -EINVAL; | ||
1919 | goto err; | ||
1920 | } | ||
1921 | /* Alloc and copy to the cqe */ | ||
1922 | bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC); | ||
1923 | if (bnx2i_work) { | ||
1924 | INIT_LIST_HEAD(&bnx2i_work->list); | ||
1925 | bnx2i_work->session = session; | ||
1926 | bnx2i_work->bnx2i_conn = bnx2i_conn; | ||
1927 | memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe)); | ||
1928 | list_add_tail(&bnx2i_work->list, &p->work_list); | ||
1929 | atomic_inc(&bnx2i_conn->work_cnt); | ||
1930 | wake_up_process(p->iothread); | ||
1931 | spin_unlock(&p->p_work_lock); | ||
1932 | goto done; | ||
1933 | } else | ||
1934 | rc = -ENOMEM; | ||
1935 | err: | ||
1936 | spin_unlock(&p->p_work_lock); | ||
1937 | bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe); | ||
1938 | done: | ||
1939 | return rc; | ||
1940 | } | ||
1941 | |||
1839 | 1942 | ||
1840 | /** | 1943 | /** |
1841 | * bnx2i_process_new_cqes - process newly DMA'ed CQE's | 1944 | * bnx2i_process_new_cqes - process newly DMA'ed CQE's |
1842 | * @bnx2i_conn: iscsi connection | 1945 | * @bnx2i_conn: bnx2i connection |
1843 | * | 1946 | * |
1844 | * this function is called by generic KCQ handler to process all pending CQE's | 1947 | * this function is called by generic KCQ handler to process all pending CQE's |
1845 | */ | 1948 | */ |
1846 | static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) | 1949 | static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) |
1847 | { | 1950 | { |
1848 | struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; | 1951 | struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; |
1849 | struct iscsi_session *session = conn->session; | 1952 | struct iscsi_session *session = conn->session; |
1850 | struct qp_info *qp = &bnx2i_conn->ep->qp; | 1953 | struct qp_info *qp; |
1851 | struct bnx2i_nop_in_msg *nopin; | 1954 | struct bnx2i_nop_in_msg *nopin; |
1852 | int tgt_async_msg; | 1955 | int tgt_async_msg; |
1956 | int cqe_cnt = 0; | ||
1853 | 1957 | ||
1958 | if (bnx2i_conn->ep == NULL) | ||
1959 | return 0; | ||
1960 | |||
1961 | qp = &bnx2i_conn->ep->qp; | ||
1962 | |||
1963 | if (!qp->cq_virt) { | ||
1964 | printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!", | ||
1965 | bnx2i_conn->hba->netdev->name); | ||
1966 | goto out; | ||
1967 | } | ||
1854 | while (1) { | 1968 | while (1) { |
1855 | nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; | 1969 | nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; |
1856 | if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) | 1970 | if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) |
@@ -1873,8 +1987,9 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) | |||
1873 | switch (nopin->op_code) { | 1987 | switch (nopin->op_code) { |
1874 | case ISCSI_OP_SCSI_CMD_RSP: | 1988 | case ISCSI_OP_SCSI_CMD_RSP: |
1875 | case ISCSI_OP_SCSI_DATA_IN: | 1989 | case ISCSI_OP_SCSI_DATA_IN: |
1876 | bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, | 1990 | /* Run the kthread engine only for data cmds |
1877 | qp->cq_cons_qe); | 1991 | All other cmds will be completed in this bh! */ |
1992 | bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin); | ||
1878 | break; | 1993 | break; |
1879 | case ISCSI_OP_LOGIN_RSP: | 1994 | case ISCSI_OP_LOGIN_RSP: |
1880 | bnx2i_process_login_resp(session, bnx2i_conn, | 1995 | bnx2i_process_login_resp(session, bnx2i_conn, |
@@ -1918,13 +2033,21 @@ static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) | |||
1918 | printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", | 2033 | printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", |
1919 | nopin->op_code); | 2034 | nopin->op_code); |
1920 | } | 2035 | } |
1921 | if (!tgt_async_msg) | 2036 | if (!tgt_async_msg) { |
1922 | bnx2i_conn->ep->num_active_cmds--; | 2037 | if (!atomic_read(&bnx2i_conn->ep->num_active_cmds)) |
2038 | printk(KERN_ALERT "bnx2i (%s): no active cmd! " | ||
2039 | "op 0x%x\n", | ||
2040 | bnx2i_conn->hba->netdev->name, | ||
2041 | nopin->op_code); | ||
2042 | else | ||
2043 | atomic_dec(&bnx2i_conn->ep->num_active_cmds); | ||
2044 | } | ||
1923 | cqe_out: | 2045 | cqe_out: |
1924 | /* clear out in production version only, till beta keep opcode | 2046 | /* clear out in production version only, till beta keep opcode |
1925 | * field intact, will be helpful in debugging (context dump) | 2047 | * field intact, will be helpful in debugging (context dump) |
1926 | * nopin->op_code = 0; | 2048 | * nopin->op_code = 0; |
1927 | */ | 2049 | */ |
2050 | cqe_cnt++; | ||
1928 | qp->cqe_exp_seq_sn++; | 2051 | qp->cqe_exp_seq_sn++; |
1929 | if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) | 2052 | if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) |
1930 | qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; | 2053 | qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; |
@@ -1937,6 +2060,8 @@ cqe_out: | |||
1937 | qp->cq_cons_idx++; | 2060 | qp->cq_cons_idx++; |
1938 | } | 2061 | } |
1939 | } | 2062 | } |
2063 | out: | ||
2064 | return cqe_cnt; | ||
1940 | } | 2065 | } |
1941 | 2066 | ||
1942 | /** | 2067 | /** |
@@ -1952,6 +2077,7 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, | |||
1952 | { | 2077 | { |
1953 | struct bnx2i_conn *bnx2i_conn; | 2078 | struct bnx2i_conn *bnx2i_conn; |
1954 | u32 iscsi_cid; | 2079 | u32 iscsi_cid; |
2080 | int nxt_idx; | ||
1955 | 2081 | ||
1956 | iscsi_cid = new_cqe_kcqe->iscsi_conn_id; | 2082 | iscsi_cid = new_cqe_kcqe->iscsi_conn_id; |
1957 | bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); | 2083 | bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); |
@@ -1964,9 +2090,12 @@ static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, | |||
1964 | printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); | 2090 | printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); |
1965 | return; | 2091 | return; |
1966 | } | 2092 | } |
2093 | |||
1967 | bnx2i_process_new_cqes(bnx2i_conn); | 2094 | bnx2i_process_new_cqes(bnx2i_conn); |
1968 | bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); | 2095 | nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, |
1969 | bnx2i_process_new_cqes(bnx2i_conn); | 2096 | CNIC_ARM_CQE_FP); |
2097 | if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn)) | ||
2098 | bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); | ||
1970 | } | 2099 | } |
1971 | 2100 | ||
1972 | 2101 | ||
@@ -2312,7 +2441,7 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, | |||
2312 | printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " | 2441 | printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " |
2313 | "opcode\n", hba->netdev->name); | 2442 | "opcode\n", hba->netdev->name); |
2314 | else if (ofld_kcqe->completion_status == | 2443 | else if (ofld_kcqe->completion_status == |
2315 | ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) | 2444 | ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) |
2316 | /* error status code valid only for 5771x chipset */ | 2445 | /* error status code valid only for 5771x chipset */ |
2317 | ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; | 2446 | ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; |
2318 | else | 2447 | else |
@@ -2511,7 +2640,7 @@ static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) | |||
2511 | 2640 | ||
2512 | 2641 | ||
2513 | static int bnx2i_send_nl_mesg(void *context, u32 msg_type, | 2642 | static int bnx2i_send_nl_mesg(void *context, u32 msg_type, |
2514 | char *buf, u16 buflen) | 2643 | char *buf, u16 buflen) |
2515 | { | 2644 | { |
2516 | struct bnx2i_hba *hba = context; | 2645 | struct bnx2i_hba *hba = context; |
2517 | int rc; | 2646 | int rc; |
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 6adbdc34a9a5..0f7fb14c78ab 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c | |||
@@ -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 |
@@ -362,6 +371,91 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) | |||
362 | 371 | ||
363 | 372 | ||
364 | /** | 373 | /** |
374 | * bnx2i_percpu_thread_create - Create a receive thread for an | ||
375 | * online CPU | ||
376 | * | ||
377 | * @cpu: cpu index for the online cpu | ||
378 | */ | ||
379 | static void bnx2i_percpu_thread_create(unsigned int cpu) | ||
380 | { | ||
381 | struct bnx2i_percpu_s *p; | ||
382 | struct task_struct *thread; | ||
383 | |||
384 | p = &per_cpu(bnx2i_percpu, cpu); | ||
385 | |||
386 | thread = kthread_create(bnx2i_percpu_io_thread, (void *)p, | ||
387 | "bnx2i_thread/%d", cpu); | ||
388 | /* bind thread to the cpu */ | ||
389 | if (likely(!IS_ERR(thread))) { | ||
390 | kthread_bind(thread, cpu); | ||
391 | p->iothread = thread; | ||
392 | wake_up_process(thread); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | |||
397 | static void bnx2i_percpu_thread_destroy(unsigned int cpu) | ||
398 | { | ||
399 | struct bnx2i_percpu_s *p; | ||
400 | struct task_struct *thread; | ||
401 | struct bnx2i_work *work, *tmp; | ||
402 | |||
403 | /* Prevent any new work from being queued for this CPU */ | ||
404 | p = &per_cpu(bnx2i_percpu, cpu); | ||
405 | spin_lock_bh(&p->p_work_lock); | ||
406 | thread = p->iothread; | ||
407 | p->iothread = NULL; | ||
408 | |||
409 | /* Free all work in the list */ | ||
410 | list_for_each_entry_safe(work, tmp, &p->work_list, list) { | ||
411 | list_del_init(&work->list); | ||
412 | bnx2i_process_scsi_cmd_resp(work->session, | ||
413 | work->bnx2i_conn, &work->cqe); | ||
414 | kfree(work); | ||
415 | } | ||
416 | |||
417 | spin_unlock_bh(&p->p_work_lock); | ||
418 | if (thread) | ||
419 | kthread_stop(thread); | ||
420 | } | ||
421 | |||
422 | |||
423 | /** | ||
424 | * bnx2i_cpu_callback - Handler for CPU hotplug events | ||
425 | * | ||
426 | * @nfb: The callback data block | ||
427 | * @action: The event triggering the callback | ||
428 | * @hcpu: The index of the CPU that the event is for | ||
429 | * | ||
430 | * This creates or destroys per-CPU data for iSCSI | ||
431 | * | ||
432 | * Returns NOTIFY_OK always. | ||
433 | */ | ||
434 | static int bnx2i_cpu_callback(struct notifier_block *nfb, | ||
435 | unsigned long action, void *hcpu) | ||
436 | { | ||
437 | unsigned cpu = (unsigned long)hcpu; | ||
438 | |||
439 | switch (action) { | ||
440 | case CPU_ONLINE: | ||
441 | case CPU_ONLINE_FROZEN: | ||
442 | printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n", | ||
443 | cpu); | ||
444 | bnx2i_percpu_thread_create(cpu); | ||
445 | break; | ||
446 | case CPU_DEAD: | ||
447 | case CPU_DEAD_FROZEN: | ||
448 | printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu); | ||
449 | bnx2i_percpu_thread_destroy(cpu); | ||
450 | break; | ||
451 | default: | ||
452 | break; | ||
453 | } | ||
454 | return NOTIFY_OK; | ||
455 | } | ||
456 | |||
457 | |||
458 | /** | ||
365 | * bnx2i_mod_init - module init entry point | 459 | * bnx2i_mod_init - module init entry point |
366 | * | 460 | * |
367 | * initialize any driver wide global data structures such as endpoint pool, | 461 | * initialize any driver wide global data structures such as endpoint pool, |
@@ -371,6 +465,8 @@ void bnx2i_ulp_exit(struct cnic_dev *dev) | |||
371 | static int __init bnx2i_mod_init(void) | 465 | static int __init bnx2i_mod_init(void) |
372 | { | 466 | { |
373 | int err; | 467 | int err; |
468 | unsigned cpu = 0; | ||
469 | struct bnx2i_percpu_s *p; | ||
374 | 470 | ||
375 | printk(KERN_INFO "%s", version); | 471 | printk(KERN_INFO "%s", version); |
376 | 472 | ||
@@ -393,6 +489,20 @@ static int __init bnx2i_mod_init(void) | |||
393 | goto unreg_xport; | 489 | goto unreg_xport; |
394 | } | 490 | } |
395 | 491 | ||
492 | /* Create percpu kernel threads to handle iSCSI I/O completions */ | ||
493 | for_each_possible_cpu(cpu) { | ||
494 | p = &per_cpu(bnx2i_percpu, cpu); | ||
495 | INIT_LIST_HEAD(&p->work_list); | ||
496 | spin_lock_init(&p->p_work_lock); | ||
497 | p->iothread = NULL; | ||
498 | } | ||
499 | |||
500 | for_each_online_cpu(cpu) | ||
501 | bnx2i_percpu_thread_create(cpu); | ||
502 | |||
503 | /* Initialize per CPU interrupt thread */ | ||
504 | register_hotcpu_notifier(&bnx2i_cpu_notifier); | ||
505 | |||
396 | return 0; | 506 | return 0; |
397 | 507 | ||
398 | unreg_xport: | 508 | unreg_xport: |
@@ -413,6 +523,7 @@ out: | |||
413 | static void __exit bnx2i_mod_exit(void) | 523 | static void __exit bnx2i_mod_exit(void) |
414 | { | 524 | { |
415 | struct bnx2i_hba *hba; | 525 | struct bnx2i_hba *hba; |
526 | unsigned cpu = 0; | ||
416 | 527 | ||
417 | mutex_lock(&bnx2i_dev_lock); | 528 | mutex_lock(&bnx2i_dev_lock); |
418 | while (!list_empty(&adapter_list)) { | 529 | while (!list_empty(&adapter_list)) { |
@@ -430,6 +541,11 @@ static void __exit bnx2i_mod_exit(void) | |||
430 | } | 541 | } |
431 | mutex_unlock(&bnx2i_dev_lock); | 542 | mutex_unlock(&bnx2i_dev_lock); |
432 | 543 | ||
544 | unregister_hotcpu_notifier(&bnx2i_cpu_notifier); | ||
545 | |||
546 | for_each_online_cpu(cpu) | ||
547 | bnx2i_percpu_thread_destroy(cpu); | ||
548 | |||
433 | iscsi_unregister_transport(&bnx2i_iscsi_transport); | 549 | iscsi_unregister_transport(&bnx2i_iscsi_transport); |
434 | cnic_unregister_driver(CNIC_ULP_ISCSI); | 550 | cnic_unregister_driver(CNIC_ULP_ISCSI); |
435 | } | 551 | } |
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 041928b23cb0..9d40f3279634 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c | |||
@@ -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, |