From 7163ea815170f8c5d56ead27d7e6fa3fa1f9844b Mon Sep 17 00:00:00 2001 From: Anirban Chakraborty Date: Wed, 5 Aug 2009 09:18:40 -0700 Subject: [SCSI] qla2xxx: Fix to ensure driver works in sinlge queue mode if multiqueue fails When the multiqueue mode fails to work, the driver falls back on single queue mode. This ensures that the firmware is reinitialized with single queue options and all the resources are readjusted accordingly. Signed-off-by: Anirban Chakraborty Signed-off-by: James Bottomley Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f0396e79b6f..d7b271339a5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -287,9 +287,12 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) int ques, req, ret; struct qla_hw_data *ha = vha->hw; + if (!(ha->fw_attributes & BIT_6)) { + qla_printk(KERN_INFO, ha, + "Firmware is not multi-queue capable\n"); + goto fail; + } if (ql2xmultique_tag) { - /* CPU affinity mode */ - ha->wq = create_workqueue("qla2xxx_wq"); /* create a request queue for IO */ options |= BIT_7; req = qla25xx_create_req_que(ha, options, 0, 0, -1, @@ -299,6 +302,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) "Can't create request queue\n"); goto fail; } + ha->wq = create_workqueue("qla2xxx_wq"); vha->req = ha->req_q_map[req]; options |= BIT_1; for (ques = 1; ques < ha->max_rsp_queues; ques++) { @@ -309,6 +313,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) goto fail2; } } + ha->flags.cpu_affinity_enabled = 1; + DEBUG2(qla_printk(KERN_INFO, ha, "CPU affinity mode enabled, no. of response" " queues:%d, no. of request queues:%d\n", @@ -317,8 +323,13 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) return 0; fail2: qla25xx_delete_queues(vha); + destroy_workqueue(ha->wq); + ha->wq = NULL; fail: ha->mqenable = 0; + kfree(ha->req_q_map); + kfree(ha->rsp_q_map); + ha->max_req_queues = ha->max_rsp_queues = 1; return 1; } @@ -1923,6 +1934,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto probe_init_failed; /* Alloc arrays of request and response ring ptrs */ +que_init: if (!qla2x00_alloc_queues(ha)) { qla_printk(KERN_WARNING, ha, "[ERROR] Failed to allocate memory for queue" @@ -1959,11 +1971,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - if (ha->mqenable) - if (qla25xx_setup_mode(base_vha)) + if (ha->mqenable) { + if (qla25xx_setup_mode(base_vha)) { qla_printk(KERN_WARNING, ha, "Can't create queues, falling back to single" " queue mode\n"); + goto que_init; + } + } if (ha->flags.running_gold_fw) goto skip_dpc; -- cgit v1.2.3 From cf53b069f52ae3f83dec1acd339e3c3a2e979478 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Thu, 20 Aug 2009 11:06:04 -0700 Subject: [SCSI] qla2xxx: Generalize srb structure usage. Lay groundwork for adding alternative asynchronous operations by generalize and extending the SRB structure. This allows for follow-on patches to add support for: - Asynchronous logins. - ELS/CT passthru requests. - Loopback requests. - Non-blocking mailbox commands (ABTS, Task Management, etc). Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d7b271339a5..b6c088caf35 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -473,6 +473,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, sp->flags = 0; CMD_SP(cmd) = (void *)sp; cmd->scsi_done = done; + sp->ctx = NULL; return sp; } @@ -709,6 +710,8 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport) continue; if (sp->fcport != fcport) continue; + if (sp->ctx) + continue; spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { @@ -794,7 +797,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (sp == NULL) continue; - + if (sp->ctx) + continue; if (sp->cmd != cmd) continue; @@ -859,7 +863,8 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, sp = req->outstanding_cmds[cnt]; if (!sp) continue; - + if (sp->ctx) + continue; if (vha->vp_idx != sp->fcport->vha->vp_idx) continue; match = 0; @@ -2986,6 +2991,8 @@ qla2x00_timer(scsi_qla_host_t *vha) sp = req->outstanding_cmds[index]; if (!sp) continue; + if (sp->ctx) + continue; sfcp = sp->fcport; if (!(sfcp->flags & FCF_TAPE_PRESENT)) continue; -- cgit v1.2.3 From ac280b670e6d6666667aba02324e2fc50bd96ae7 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Thu, 20 Aug 2009 11:06:05 -0700 Subject: [SCSI] qla2xxx: Add asynchronous-login support. ISPs which support this feature include 23xx and above. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 72 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index b6c088caf35..5fd7adbff30 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1170,6 +1170,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) int que, cnt; unsigned long flags; srb_t *sp; + struct srb_ctx *ctx; struct qla_hw_data *ha = vha->hw; struct req_que *req; @@ -1182,8 +1183,14 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) sp = req->outstanding_cmds[cnt]; if (sp) { req->outstanding_cmds[cnt] = NULL; - sp->cmd->result = res; - qla2x00_sp_compl(ha, sp); + if (!sp->ctx) { + sp->cmd->result = res; + qla2x00_sp_compl(ha, sp); + } else { + ctx = sp->ctx; + del_timer_sync(&ctx->timer); + ctx->free(sp); + } } } } @@ -2618,7 +2625,31 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) return qla2x00_post_work(vha, e); } -static void +#define qla2x00_post_async_work(name, type) \ +int qla2x00_post_async_##name##_work( \ + struct scsi_qla_host *vha, \ + fc_port_t *fcport, uint16_t *data) \ +{ \ + struct qla_work_evt *e; \ + \ + e = qla2x00_alloc_work(vha, type); \ + if (!e) \ + return QLA_FUNCTION_FAILED; \ + \ + e->u.logio.fcport = fcport; \ + if (data) { \ + e->u.logio.data[0] = data[0]; \ + e->u.logio.data[1] = data[1]; \ + } \ + return qla2x00_post_work(vha, e); \ +} + +qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); +qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE); +qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); +qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); + +void qla2x00_do_work(struct scsi_qla_host *vha) { struct qla_work_evt *e, *tmp; @@ -2640,6 +2671,21 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_IDC_ACK: qla81xx_idc_ack(vha, e->u.idc_ack.mb); break; + case QLA_EVT_ASYNC_LOGIN: + qla2x00_async_login(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_LOGIN_DONE: + qla2x00_async_login_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_LOGOUT: + qla2x00_async_logout(vha, e->u.logio.fcport); + break; + case QLA_EVT_ASYNC_LOGOUT_DONE: + qla2x00_async_logout_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -2655,6 +2701,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) int status; uint16_t next_loopid = 0; struct qla_hw_data *ha = vha->hw; + uint16_t data[2]; list_for_each_entry(fcport, &vha->vp_fcports, list) { /* @@ -2664,6 +2711,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) if (atomic_read(&fcport->state) != FCS_ONLINE && fcport->login_retry) { + fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_TAPE_PRESENT) ha->isp_ops->fabric_logout(vha, @@ -2672,13 +2720,22 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->d_id.b.area, fcport->d_id.b.al_pa); - status = qla2x00_fabric_login(vha, fcport, - &next_loopid); + if (IS_ALOGIO_CAPABLE(ha)) { + data[0] = 0; + data[1] = QLA_LOGIO_LOGIN_RETRIED; + status = qla2x00_post_async_login_work( + vha, fcport, data); + if (status == QLA_SUCCESS) + continue; + /* Attempt a retry. */ + status = 1; + } else + status = qla2x00_fabric_login(vha, + fcport, &next_loopid); } else status = qla2x00_local_device_login(vha, fcport); - fcport->login_retry--; if (status == QLA_SUCCESS) { fcport->old_loop_id = fcport->loop_id; @@ -2851,6 +2908,9 @@ qla2x00_do_dpc(void *data) */ ha->dpc_active = 0; + /* Cleanup any residual CTX SRBs. */ + qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); + return 0; } -- cgit v1.2.3 From 8474f3a02a18e18459663ad88951822c62a45068 Mon Sep 17 00:00:00 2001 From: Santosh Vernekar Date: Tue, 25 Aug 2009 11:36:16 -0700 Subject: [SCSI] qla2xxx: Correctly set FCF_TAPE_PRESENT flag based on scsi-device. In fabric-login based on iop BIT_8 firmware notifies presence of a FCP2 device and not necessarily a TAPE device. So instead of setting FCF_TAPE_PRESENT flag there we set it using scsi_device->type after mid-layer scan recognises "type" of the device. It also adds a new flag FCF_FCP2_DEVICE for any future use. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5fd7adbff30..649fd75d37b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1216,6 +1216,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_qla_host_t *vha = shost_priv(sdev->host); struct qla_hw_data *ha = vha->hw; struct fc_rport *rport = starget_to_rport(sdev->sdev_target); + fc_port_t *fcport = *(fc_port_t **)rport->dd_data; struct req_que *req = vha->req; if (sdev->tagged_supported) @@ -1224,6 +1225,8 @@ qla2xxx_slave_configure(struct scsi_device *sdev) scsi_deactivate_tcq(sdev, req->max_q_depth); rport->dev_loss_tmo = ha->port_down_retry_count; + if (sdev->type == TYPE_TAPE) + fcport->flags |= FCF_TAPE_PRESENT; return 0; } -- cgit v1.2.3 From d970432c48ab8dd28216e80942723aeb505b623e Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Tue, 25 Aug 2009 11:36:18 -0700 Subject: [SCSI] qla2xxx: Correct qla2x00_eh_wait_on_command() to wait correctly. Original code would break-out of loop after only one iteration. Signed-off-by: Lalit Chandivade Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 649fd75d37b..ea9f91756c1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -568,11 +568,8 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) unsigned long wait_iter = ABORT_WAIT_ITER; int ret = QLA_SUCCESS; - while (CMD_SP(cmd)) { + while (CMD_SP(cmd) && wait_iter--) { msleep(ABORT_POLLING_PERIOD); - - if (--wait_iter) - break; } if (CMD_SP(cmd)) ret = QLA_FUNCTION_FAILED; -- cgit v1.2.3 From 0d6e61bc6a4f3f54444b088ae6d447f1703a21dd Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 25 Aug 2009 11:36:19 -0700 Subject: [SCSI] qla2xxx: Correct various NPIV issues. * Consolidate vport-count processing. * Correct vp_idx restrictions during RSCN processing. * Push topology verification check to qla2x00_do_dpc_all_vps(). * Don't skip vport full-login-lip/lip-reset mailbox handling. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ea9f91756c1..21022901958 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1119,8 +1119,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) struct fc_port *fcport; struct qla_hw_data *ha = vha->hw; - if (ha->flags.enable_lip_full_login && !vha->vp_idx && - !IS_QLA81XX(ha)) { + if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) { ret = qla2x00_full_login_lip(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -1133,7 +1132,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) qla2x00_wait_for_loop_ready(vha); } - if (ha->flags.enable_lip_reset && !vha->vp_idx) { + if (ha->flags.enable_lip_reset) { ret = qla2x00_lip_reset(vha); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): failed: " @@ -2264,8 +2263,9 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) fc_port_t *fcport; list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (vha->vp_idx != fcport->vp_idx) + if (vha->vp_idx != 0 && vha->vp_idx != fcport->vp_idx) continue; + /* * No point in marking the device as lost, if the device is * already DEAD. @@ -2273,10 +2273,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) continue; if (atomic_read(&fcport->state) == FCS_ONLINE) { - atomic_set(&fcport->state, FCS_DEVICE_LOST); - qla2x00_schedule_rport_del(vha, fcport, defer); - } else - atomic_set(&fcport->state, FCS_DEVICE_LOST); + if (defer) + qla2x00_schedule_rport_del(vha, fcport, defer); + else if (vha->vp_idx == fcport->vp_idx) + qla2x00_schedule_rport_del(vha, fcport, defer); + } + atomic_set(&fcport->state, FCS_DEVICE_LOST); } } @@ -3069,8 +3071,7 @@ qla2x00_timer(scsi_qla_host_t *vha) /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - if (!(vha->device_flags & DFLG_NO_CABLE) && - !vha->vp_idx) { + if (!(vha->device_flags & DFLG_NO_CABLE)) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", vha->host_no)); -- cgit v1.2.3 From 67becc0041615651b75e4496204a0835a8c345a8 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 25 Aug 2009 11:36:20 -0700 Subject: [SCSI] qla2xxx: Properly delete rports attached to a vport. Original code would inadvertently skip the deferred fc_remote_port_delete() call for rports hanging off any vport. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_os.c') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 21022901958..b79fca7d461 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2181,17 +2181,19 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, int defer) { struct fc_rport *rport; + scsi_qla_host_t *base_vha; if (!fcport->rport) return; rport = fcport->rport; if (defer) { + base_vha = pci_get_drvdata(vha->hw->pdev); spin_lock_irq(vha->host->host_lock); fcport->drport = rport; spin_unlock_irq(vha->host->host_lock); - set_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); + set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); + qla2xxx_wake_dpc(base_vha); } else fc_remote_port_delete(rport); } -- cgit v1.2.3