diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 4 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 22 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 22 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 10 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 11 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 78 |
7 files changed, 140 insertions, 9 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index bda6658d4fbf..f3536e56dce4 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -1531,7 +1531,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) | |||
1531 | qla24xx_vport_disable(fc_vport, disable); | 1531 | qla24xx_vport_disable(fc_vport, disable); |
1532 | 1532 | ||
1533 | ret = 0; | 1533 | ret = 0; |
1534 | if (ha->cur_vport_count <= ha->flex_port_count | 1534 | if (ha->cur_vport_count <= ha->flex_port_count || ql2xmultique_tag |
1535 | || ha->max_req_queues == 1 || !ha->npiv_info) | 1535 | || ha->max_req_queues == 1 || !ha->npiv_info) |
1536 | goto vport_queue; | 1536 | goto vport_queue; |
1537 | /* Create a request queue in QoS mode for the vport */ | 1537 | /* Create a request queue in QoS mode for the vport */ |
@@ -1599,7 +1599,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) | |||
1599 | vha->host_no, vha->vp_idx, vha)); | 1599 | vha->host_no, vha->vp_idx, vha)); |
1600 | } | 1600 | } |
1601 | 1601 | ||
1602 | if (vha->req->id) { | 1602 | if (vha->req->id && !ql2xmultique_tag) { |
1603 | if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) | 1603 | if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) |
1604 | qla_printk(KERN_WARNING, ha, | 1604 | qla_printk(KERN_WARNING, ha, |
1605 | "Queue delete failed.\n"); | 1605 | "Queue delete failed.\n"); |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 57d659cf99ee..09190ba411fd 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2171,6 +2171,7 @@ struct rsp_que { | |||
2171 | struct qla_msix_entry *msix; | 2171 | struct qla_msix_entry *msix; |
2172 | struct req_que *req; | 2172 | struct req_que *req; |
2173 | srb_t *status_srb; /* status continuation entry */ | 2173 | srb_t *status_srb; /* status continuation entry */ |
2174 | struct work_struct q_work; | ||
2174 | }; | 2175 | }; |
2175 | 2176 | ||
2176 | /* Request queue data structure */ | 2177 | /* Request queue data structure */ |
@@ -2539,6 +2540,7 @@ struct qla_hw_data { | |||
2539 | struct qla_chip_state_84xx *cs84xx; | 2540 | struct qla_chip_state_84xx *cs84xx; |
2540 | struct qla_statistics qla_stats; | 2541 | struct qla_statistics qla_stats; |
2541 | struct isp_operations *isp_ops; | 2542 | struct isp_operations *isp_ops; |
2543 | struct workqueue_struct *wq; | ||
2542 | }; | 2544 | }; |
2543 | 2545 | ||
2544 | /* | 2546 | /* |
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 94b69d86482d..7b15ded991cb 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c | |||
@@ -15,6 +15,7 @@ static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *, | |||
15 | struct rsp_que *rsp); | 15 | struct rsp_que *rsp); |
16 | static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *); | 16 | static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *); |
17 | 17 | ||
18 | static void qla25xx_set_que(srb_t *, struct req_que **, struct rsp_que **); | ||
18 | /** | 19 | /** |
19 | * qla2x00_get_cmd_direction() - Determine control_flag data direction. | 20 | * qla2x00_get_cmd_direction() - Determine control_flag data direction. |
20 | * @cmd: SCSI command | 21 | * @cmd: SCSI command |
@@ -726,8 +727,7 @@ qla24xx_start_scsi(srb_t *sp) | |||
726 | /* Setup device pointers. */ | 727 | /* Setup device pointers. */ |
727 | ret = 0; | 728 | ret = 0; |
728 | 729 | ||
729 | req = vha->req; | 730 | qla25xx_set_que(sp, &req, &rsp); |
730 | rsp = ha->rsp_q_map[0]; | ||
731 | sp->que = req; | 731 | sp->que = req; |
732 | 732 | ||
733 | /* So we know we haven't pci_map'ed anything yet */ | 733 | /* So we know we haven't pci_map'ed anything yet */ |
@@ -850,3 +850,21 @@ queuing_error: | |||
850 | 850 | ||
851 | return QLA_FUNCTION_FAILED; | 851 | return QLA_FUNCTION_FAILED; |
852 | } | 852 | } |
853 | |||
854 | static void qla25xx_set_que(srb_t *sp, struct req_que **req, | ||
855 | struct rsp_que **rsp) | ||
856 | { | ||
857 | struct scsi_cmnd *cmd = sp->cmd; | ||
858 | struct scsi_qla_host *vha = sp->fcport->vha; | ||
859 | struct qla_hw_data *ha = sp->fcport->vha->hw; | ||
860 | int affinity = cmd->request->cpu; | ||
861 | |||
862 | if (ql2xmultique_tag && affinity >= 0 && | ||
863 | affinity < ha->max_rsp_queues - 1) { | ||
864 | *rsp = ha->rsp_q_map[affinity + 1]; | ||
865 | *req = ha->req_q_map[1]; | ||
866 | } else { | ||
867 | *req = vha->req; | ||
868 | *rsp = ha->rsp_q_map[0]; | ||
869 | } | ||
870 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index c8e906c702a1..41e50c2bec0f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
@@ -1718,6 +1718,25 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) | |||
1718 | } | 1718 | } |
1719 | 1719 | ||
1720 | static irqreturn_t | 1720 | static irqreturn_t |
1721 | qla25xx_msix_rsp_q(int irq, void *dev_id) | ||
1722 | { | ||
1723 | struct qla_hw_data *ha; | ||
1724 | struct rsp_que *rsp; | ||
1725 | |||
1726 | rsp = (struct rsp_que *) dev_id; | ||
1727 | if (!rsp) { | ||
1728 | printk(KERN_INFO | ||
1729 | "%s(): NULL response queue pointer\n", __func__); | ||
1730 | return IRQ_NONE; | ||
1731 | } | ||
1732 | ha = rsp->hw; | ||
1733 | |||
1734 | queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work); | ||
1735 | |||
1736 | return IRQ_HANDLED; | ||
1737 | } | ||
1738 | |||
1739 | static irqreturn_t | ||
1721 | qla24xx_msix_default(int irq, void *dev_id) | 1740 | qla24xx_msix_default(int irq, void *dev_id) |
1722 | { | 1741 | { |
1723 | scsi_qla_host_t *vha; | 1742 | scsi_qla_host_t *vha; |
@@ -1806,9 +1825,10 @@ struct qla_init_msix_entry { | |||
1806 | irq_handler_t handler; | 1825 | irq_handler_t handler; |
1807 | }; | 1826 | }; |
1808 | 1827 | ||
1809 | static struct qla_init_msix_entry msix_entries[2] = { | 1828 | static struct qla_init_msix_entry msix_entries[3] = { |
1810 | { "qla2xxx (default)", qla24xx_msix_default }, | 1829 | { "qla2xxx (default)", qla24xx_msix_default }, |
1811 | { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, | 1830 | { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, |
1831 | { "qla2xxx (multiq)", qla25xx_msix_rsp_q }, | ||
1812 | }; | 1832 | }; |
1813 | 1833 | ||
1814 | static void | 1834 | static void |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bfdc89f8569b..366522e8a766 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -1497,7 +1497,10 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, | |||
1497 | 1497 | ||
1498 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | 1498 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); |
1499 | 1499 | ||
1500 | req = vha->req; | 1500 | if (ql2xmultique_tag) |
1501 | req = ha->req_q_map[0]; | ||
1502 | else | ||
1503 | req = vha->req; | ||
1501 | rsp = req->rsp; | 1504 | rsp = req->rsp; |
1502 | 1505 | ||
1503 | lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); | 1506 | lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); |
@@ -2311,7 +2314,10 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, | |||
2311 | vha = fcport->vha; | 2314 | vha = fcport->vha; |
2312 | ha = vha->hw; | 2315 | ha = vha->hw; |
2313 | req = vha->req; | 2316 | req = vha->req; |
2314 | rsp = req->rsp; | 2317 | if (ql2xmultique_tag) |
2318 | rsp = ha->rsp_q_map[tag + 1]; | ||
2319 | else | ||
2320 | rsp = req->rsp; | ||
2315 | tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); | 2321 | tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); |
2316 | if (tsk == NULL) { | 2322 | if (tsk == NULL) { |
2317 | DEBUG2_3(printk("%s(%ld): failed to allocate Task Management " | 2323 | DEBUG2_3(printk("%s(%ld): failed to allocate Task Management " |
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 9c08479c3e1b..650bcef08f2a 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c | |||
@@ -633,6 +633,15 @@ que_failed: | |||
633 | return 0; | 633 | return 0; |
634 | } | 634 | } |
635 | 635 | ||
636 | static void qla_do_work(struct work_struct *work) | ||
637 | { | ||
638 | struct rsp_que *rsp = container_of(work, struct rsp_que, q_work); | ||
639 | struct scsi_qla_host *vha; | ||
640 | |||
641 | vha = qla25xx_get_host(rsp); | ||
642 | qla24xx_process_response_queue(vha, rsp); | ||
643 | } | ||
644 | |||
636 | /* create response queue */ | 645 | /* create response queue */ |
637 | int | 646 | int |
638 | qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, | 647 | qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, |
@@ -711,6 +720,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, | |||
711 | rsp->req = NULL; | 720 | rsp->req = NULL; |
712 | 721 | ||
713 | qla2x00_init_response_q_entries(rsp); | 722 | qla2x00_init_response_q_entries(rsp); |
723 | if (rsp->hw->wq) | ||
724 | INIT_WORK(&rsp->q_work, qla_do_work); | ||
714 | return rsp->id; | 725 | return rsp->id; |
715 | 726 | ||
716 | que_failed: | 727 | que_failed: |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index e2647e02dac9..d6817df95e30 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -96,6 +96,13 @@ MODULE_PARM_DESC(ql2xmaxqueues, | |||
96 | "Enables MQ settings " | 96 | "Enables MQ settings " |
97 | "Default is 1 for single queue. Set it to number \ | 97 | "Default is 1 for single queue. Set it to number \ |
98 | of queues in MQ mode."); | 98 | of queues in MQ mode."); |
99 | |||
100 | int ql2xmultique_tag; | ||
101 | module_param(ql2xmultique_tag, int, S_IRUGO|S_IRUSR); | ||
102 | MODULE_PARM_DESC(ql2xmultique_tag, | ||
103 | "Enables CPU affinity settings for the driver " | ||
104 | "Default is 0 for no affinity of request and response IO. " | ||
105 | "Set it to 1 to turn on the cpu affinity."); | ||
99 | /* | 106 | /* |
100 | * SCSI host template entry points | 107 | * SCSI host template entry points |
101 | */ | 108 | */ |
@@ -256,6 +263,47 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) | |||
256 | ha->rsp_q_map = NULL; | 263 | ha->rsp_q_map = NULL; |
257 | } | 264 | } |
258 | 265 | ||
266 | static int qla25xx_setup_mode(struct scsi_qla_host *vha) | ||
267 | { | ||
268 | uint16_t options = 0; | ||
269 | int ques, req, ret; | ||
270 | struct qla_hw_data *ha = vha->hw; | ||
271 | |||
272 | if (ql2xmultique_tag) { | ||
273 | /* CPU affinity mode */ | ||
274 | ha->wq = create_workqueue("qla2xxx_wq"); | ||
275 | /* create a request queue for IO */ | ||
276 | options |= BIT_7; | ||
277 | req = qla25xx_create_req_que(ha, options, 0, 0, -1, | ||
278 | QLA_DEFAULT_QUE_QOS); | ||
279 | if (!req) { | ||
280 | qla_printk(KERN_WARNING, ha, | ||
281 | "Can't create request queue\n"); | ||
282 | goto fail; | ||
283 | } | ||
284 | vha->req = ha->req_q_map[req]; | ||
285 | options |= BIT_1; | ||
286 | for (ques = 1; ques < ha->max_rsp_queues; ques++) { | ||
287 | ret = qla25xx_create_rsp_que(ha, options, 0, 0, req); | ||
288 | if (!ret) { | ||
289 | qla_printk(KERN_WARNING, ha, | ||
290 | "Response Queue create failed\n"); | ||
291 | goto fail2; | ||
292 | } | ||
293 | } | ||
294 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
295 | "CPU affinity mode enabled, no. of response" | ||
296 | " queues:%d, no. of request queues:%d\n", | ||
297 | ha->max_rsp_queues, ha->max_req_queues)); | ||
298 | } | ||
299 | return 0; | ||
300 | fail2: | ||
301 | qla25xx_delete_queues(vha); | ||
302 | fail: | ||
303 | ha->mqenable = 0; | ||
304 | return 1; | ||
305 | } | ||
306 | |||
259 | static char * | 307 | static char * |
260 | qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) | 308 | qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) |
261 | { | 309 | { |
@@ -998,6 +1046,9 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) | |||
998 | if (qla2x00_vp_abort_isp(vha)) | 1046 | if (qla2x00_vp_abort_isp(vha)) |
999 | goto eh_host_reset_lock; | 1047 | goto eh_host_reset_lock; |
1000 | } else { | 1048 | } else { |
1049 | if (ha->wq) | ||
1050 | flush_workqueue(ha->wq); | ||
1051 | |||
1001 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 1052 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
1002 | if (qla2x00_abort_isp(base_vha)) { | 1053 | if (qla2x00_abort_isp(base_vha)) { |
1003 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 1054 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
@@ -1521,6 +1572,7 @@ qla2x00_iospace_config(struct qla_hw_data *ha) | |||
1521 | { | 1572 | { |
1522 | resource_size_t pio; | 1573 | resource_size_t pio; |
1523 | uint16_t msix; | 1574 | uint16_t msix; |
1575 | int cpus; | ||
1524 | 1576 | ||
1525 | if (pci_request_selected_regions(ha->pdev, ha->bars, | 1577 | if (pci_request_selected_regions(ha->pdev, ha->bars, |
1526 | QLA2XXX_DRIVER_NAME)) { | 1578 | QLA2XXX_DRIVER_NAME)) { |
@@ -1575,7 +1627,7 @@ skip_pio: | |||
1575 | 1627 | ||
1576 | /* Determine queue resources */ | 1628 | /* Determine queue resources */ |
1577 | ha->max_req_queues = ha->max_rsp_queues = 1; | 1629 | ha->max_req_queues = ha->max_rsp_queues = 1; |
1578 | if (ql2xmaxqueues <= 1 && | 1630 | if ((ql2xmaxqueues <= 1 || ql2xmultique_tag < 1) && |
1579 | (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) | 1631 | (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) |
1580 | goto mqiobase_exit; | 1632 | goto mqiobase_exit; |
1581 | ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), | 1633 | ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), |
@@ -1584,12 +1636,21 @@ skip_pio: | |||
1584 | /* Read MSIX vector size of the board */ | 1636 | /* Read MSIX vector size of the board */ |
1585 | pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); | 1637 | pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); |
1586 | ha->msix_count = msix; | 1638 | ha->msix_count = msix; |
1587 | if (ql2xmaxqueues > 1) { | 1639 | /* Max queues are bounded by available msix vectors */ |
1640 | /* queue 0 uses two msix vectors */ | ||
1641 | if (ql2xmultique_tag) { | ||
1642 | cpus = num_online_cpus(); | ||
1643 | ha->max_rsp_queues = (ha->msix_count - 1 - cpus) ? | ||
1644 | (cpus + 1) : (ha->msix_count - 1); | ||
1645 | ha->max_req_queues = 2; | ||
1646 | } else if (ql2xmaxqueues > 1) { | ||
1588 | ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? | 1647 | ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? |
1589 | QLA_MQ_SIZE : ql2xmaxqueues; | 1648 | QLA_MQ_SIZE : ql2xmaxqueues; |
1590 | DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no" | 1649 | DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no" |
1591 | " of request queues:%d\n", ha->max_req_queues)); | 1650 | " of request queues:%d\n", ha->max_req_queues)); |
1592 | } | 1651 | } |
1652 | qla_printk(KERN_INFO, ha, | ||
1653 | "MSI-X vector count: %d\n", msix); | ||
1593 | } else | 1654 | } else |
1594 | qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n"); | 1655 | qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n"); |
1595 | 1656 | ||
@@ -1871,6 +1932,12 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1871 | goto probe_failed; | 1932 | goto probe_failed; |
1872 | } | 1933 | } |
1873 | 1934 | ||
1935 | if (ha->mqenable) | ||
1936 | if (qla25xx_setup_mode(base_vha)) | ||
1937 | qla_printk(KERN_WARNING, ha, | ||
1938 | "Can't create queues, falling back to single" | ||
1939 | " queue mode\n"); | ||
1940 | |||
1874 | /* | 1941 | /* |
1875 | * Startup the kernel thread for this host adapter | 1942 | * Startup the kernel thread for this host adapter |
1876 | */ | 1943 | */ |
@@ -1982,6 +2049,13 @@ qla2x00_remove_one(struct pci_dev *pdev) | |||
1982 | 2049 | ||
1983 | base_vha->flags.online = 0; | 2050 | base_vha->flags.online = 0; |
1984 | 2051 | ||
2052 | /* Flush the work queue and remove it */ | ||
2053 | if (ha->wq) { | ||
2054 | flush_workqueue(ha->wq); | ||
2055 | destroy_workqueue(ha->wq); | ||
2056 | ha->wq = NULL; | ||
2057 | } | ||
2058 | |||
1985 | /* Kill the kernel thread for this host */ | 2059 | /* Kill the kernel thread for this host */ |
1986 | if (ha->dpc_thread) { | 2060 | if (ha->dpc_thread) { |
1987 | struct task_struct *t = ha->dpc_thread; | 2061 | struct task_struct *t = ha->dpc_thread; |