diff options
author | Anirban Chakraborty <anirban.chakraborty@qlogic.com> | 2009-04-07 01:33:41 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-05-20 18:21:08 -0400 |
commit | 68ca949cdb04b4dc71451a999148fbc5f187a220 (patch) | |
tree | d1d06940e8f128804529386ccea9c0757e61db0f /drivers/scsi/qla2xxx/qla_os.c | |
parent | 2afa19a9377ca61b9489e44bf50029574fbe63be (diff) |
[SCSI] qla2xxx: Add CPU affinity support.
Set the module parameter ql2xmultique_tag to 1 to enable this
feature. In this mode, the total number of response queues
created is equal to the number of online cpus. Turning the block
layer's rq_affinity mode on enables requests to be routed to the
proper cpu and at the same time it enables completion of the IO
in a response queue that is affined to the cpu in the request
path.
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 78 |
1 files changed, 76 insertions, 2 deletions
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; |