From a9083016a5314b3aeba6e0d2e814872e72168c08 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Mon, 12 Apr 2010 17:59:55 -0700 Subject: [SCSI] qla2xxx: Add ISP82XX support. Enhanced the driver to support new FCoE host bus adapter. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index db539b0c3da..f1ac62d505d 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -326,7 +326,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) /* Setup to process RIO completion. */ handle_cnt = 0; - if (IS_QLA81XX(ha)) + if (IS_QLA8XXX_TYPE(ha)) goto skip_rio; switch (mb[0]) { case MBA_SCSI_COMPLETION: @@ -544,7 +544,7 @@ skip_rio: if (IS_QLA2100(ha)) break; - if (IS_QLA81XX(ha)) + if (IS_QLA8XXX_TYPE(ha)) DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x " "%04x\n", vha->host_no, mb[1], mb[2], mb[3])); else @@ -845,7 +845,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, qla2x00_sp_compl(ha, sp); } else { DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion" - " handle(%d)\n", vha->host_no, req->id, index)); + " handle(0x%x)\n", vha->host_no, req->id, index)); qla_printk(KERN_WARNING, ha, "Invalid ISP SCSI completion handle\n"); @@ -1337,6 +1337,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) handle = (uint32_t) LSW(sts->handle); que = MSW(sts->handle); req = ha->req_q_map[que]; + /* Fast path completion. */ if (comp_status == CS_COMPLETE && scsi_status == 0) { qla2x00_process_completed_request(vha, req, handle); @@ -1806,6 +1807,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, struct rsp_que *rsp) { struct sts_entry_24xx *pkt; + struct qla_hw_data *ha = vha->hw; if (!vha->flags.online) return; @@ -1866,7 +1868,11 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, } /* Adjust ring index */ - WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); + if (IS_QLA82XX(ha)) { + struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; + WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index); + } else + WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); } static void @@ -2169,6 +2175,11 @@ static struct qla_init_msix_entry msix_entries[3] = { { "qla2xxx (multiq)", qla25xx_msix_rsp_q }, }; +static struct qla_init_msix_entry qla82xx_msix_entries[2] = { + { "qla2xxx (default)", qla82xx_msix_default }, + { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, +}; + static void qla24xx_disable_msix(struct qla_hw_data *ha) { @@ -2195,7 +2206,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) struct qla_msix_entry *qentry; entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count, - GFP_KERNEL); + GFP_KERNEL); if (!entries) return -ENOMEM; @@ -2240,8 +2251,15 @@ msix_failed: /* Enable MSI-X vectors for the base queue */ for (i = 0; i < 2; i++) { qentry = &ha->msix_entries[i]; - ret = request_irq(qentry->vector, msix_entries[i].handler, - 0, msix_entries[i].name, rsp); + if (IS_QLA82XX(ha)) { + ret = request_irq(qentry->vector, + qla82xx_msix_entries[i].handler, + 0, qla82xx_msix_entries[i].name, rsp); + } else { + ret = request_irq(qentry->vector, + msix_entries[i].handler, + 0, msix_entries[i].name, rsp); + } if (ret) { qla_printk(KERN_WARNING, ha, "MSI-X: Unable to register handler -- %x/%d.\n", @@ -2272,7 +2290,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && - !IS_QLA8432(ha) && !IS_QLA8001(ha)) + !IS_QLA8432(ha) && !IS_QLA8XXX_TYPE(ha)) goto skip_msi; if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && @@ -2302,7 +2320,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) goto clear_risc_ints; } qla_printk(KERN_WARNING, ha, - "MSI-X: Falling back-to INTa mode -- %d.\n", ret); + "MSI-X: Falling back-to MSI mode -- %d.\n", ret); skip_msix: if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && @@ -2313,7 +2331,9 @@ skip_msix: if (!ret) { DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n")); ha->flags.msi_enabled = 1; - } + } else + qla_printk(KERN_WARNING, ha, + "MSI-X: Falling back-to INTa mode -- %d.\n", ret); skip_msi: ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, @@ -2331,7 +2351,7 @@ clear_risc_ints: * FIXME: Noted that 8014s were being dropped during NK testing. * Timing deltas during MSI-X/INTa transitions? */ - if (IS_QLA81XX(ha)) + if (IS_QLA81XX(ha) || IS_QLA82XX(ha)) goto fail; spin_lock_irq(&ha->hardware_lock); if (IS_FWI2_CAPABLE(ha)) { -- cgit v1.2.3-70-g09d2 From 99b0bec7bbf3350d1a920a7138fa62c456a8ecf1 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 4 May 2010 15:01:25 -0700 Subject: [SCSI] qla2xxx: Further generalization of SRB CTX infrastructure. Prepare CTX infrastructure for additional asynchronous executions, add generic done() operator, pull CMD definitions. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 17 ++++++---- drivers/scsi/qla2xxx/qla_init.c | 43 ++++++++++++++++++------ drivers/scsi/qla2xxx/qla_isr.c | 74 ++++++++++++----------------------------- 3 files changed, 65 insertions(+), 69 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d4a53e5549b..b3cf6099600 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -214,14 +214,21 @@ typedef struct srb { /* * SRB extensions. */ -struct srb_ctx { #define SRB_LOGIN_CMD 1 #define SRB_LOGOUT_CMD 2 +#define SRB_ELS_CMD_RPT 3 +#define SRB_ELS_CMD_HST 4 +#define SRB_CT_CMD 5 + +struct srb_ctx { uint16_t type; + char *name; + struct timer_list timer; - void (*free)(srb_t *sp); - void (*timeout)(srb_t *sp); + void (*done)(srb_t *); + void (*free)(srb_t *); + void (*timeout)(srb_t *); }; struct srb_logio { @@ -231,12 +238,10 @@ struct srb_logio { #define SRB_LOGIN_COND_PLOGI BIT_1 #define SRB_LOGIN_SKIP_PRLI BIT_2 uint16_t flags; + uint16_t data[2]; }; struct srb_bsg_ctx { -#define SRB_ELS_CMD_RPT 3 -#define SRB_ELS_CMD_HST 4 -#define SRB_CT_CMD 5 uint16_t type; }; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 55540d2d4e3..c3c2c3627a7 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -117,13 +117,22 @@ qla2x00_async_logio_timeout(srb_t *sp) DEBUG2(printk(KERN_WARNING "scsi(%ld:%x): Async-%s timeout.\n", - fcport->vha->host_no, sp->handle, - lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout")); + fcport->vha->host_no, sp->handle, lio->ctx.name)); if (lio->ctx.type == SRB_LOGIN_CMD) qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); } +static void +qla2x00_async_login_ctx_done(srb_t *sp) +{ + struct srb_logio *lio = sp->ctx; + + qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport, + lio->data); + lio->ctx.free(sp); +} + int qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) @@ -141,7 +150,9 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, lio = sp->ctx; lio->ctx.type = SRB_LOGIN_CMD; + lio->ctx.name = "login"; lio->ctx.timeout = qla2x00_async_logio_timeout; + lio->ctx.done = qla2x00_async_login_ctx_done; lio->flags |= SRB_LOGIN_COND_PLOGI; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) lio->flags |= SRB_LOGIN_RETRIED; @@ -163,6 +174,16 @@ done: return rval; } +static void +qla2x00_async_logout_ctx_done(srb_t *sp) +{ + struct srb_logio *lio = sp->ctx; + + qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport, + lio->data); + lio->ctx.free(sp); +} + int qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) { @@ -179,7 +200,9 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) lio = sp->ctx; lio->ctx.type = SRB_LOGOUT_CMD; + lio->ctx.name = "logout"; lio->ctx.timeout = qla2x00_async_logio_timeout; + lio->ctx.done = qla2x00_async_logout_ctx_done; rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; @@ -202,17 +225,17 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { int rval; - uint8_t opts = 0; switch (data[0]) { case MBS_COMMAND_COMPLETE: - if (fcport->flags & FCF_FCP2_DEVICE) - opts |= BIT_1; - rval = qla2x00_get_port_database(vha, fcport, opts); - if (rval != QLA_SUCCESS) - qla2x00_mark_device_lost(vha, fcport, 1, 0); - else - qla2x00_update_fcport(vha, fcport); + if (fcport->flags & FCF_FCP2_DEVICE) { + rval = qla2x00_get_port_database(vha, fcport, BIT_1); + if (rval != QLA_SUCCESS) { + qla2x00_mark_device_lost(vha, fcport, 1, 0); + break; + } + } + qla2x00_update_fcport(vha, fcport); break; case MBS_COMMAND_ERROR: if (data[1] & QLA_LOGIO_LOGIN_RETRIED) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f1ac62d505d..037bc41eef5 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -895,34 +895,20 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, { const char func[] = "MBX-IOCB"; const char *type; - struct qla_hw_data *ha = vha->hw; fc_port_t *fcport; srb_t *sp; struct srb_logio *lio; - uint16_t data[2]; + uint16_t *data; sp = qla2x00_get_sp_from_handle(vha, func, req, mbx); if (!sp) return; - type = NULL; lio = sp->ctx; - switch (lio->ctx.type) { - case SRB_LOGIN_CMD: - type = "login"; - break; - case SRB_LOGOUT_CMD: - type = "logout"; - break; - default: - qla_printk(KERN_WARNING, ha, - "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, - lio->ctx.type); - return; - } - del_timer(&lio->ctx.timer); + type = lio->ctx.name; fcport = sp->fcport; + data = lio->data; data[0] = data[1] = 0; if (mbx->entry_status) { @@ -938,7 +924,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, data[0] = MBS_COMMAND_ERROR; data[1] = lio->flags & SRB_LOGIN_RETRIED ? QLA_LOGIO_LOGIN_RETRIED: 0; - goto done_post_logio_done_work; + goto logio_done; } if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { @@ -948,10 +934,14 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(mbx->mb1))); data[0] = MBS_COMMAND_COMPLETE; - if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1) - fcport->flags |= FCF_FCP2_DEVICE; + if (lio->ctx.type == SRB_LOGIN_CMD) + fcport->port_type = FCT_TARGET; + if (le16_to_cpu(mbx->mb1) & BIT_0) + fcport->port_type = FCT_INITIATOR; + if (le16_to_cpu(mbx->mb1) & BIT_1) + fcport->flags |= FCF_FCP2_DEVICE; - goto done_post_logio_done_work; + goto logio_done; } data[0] = le16_to_cpu(mbx->mb0); @@ -976,12 +966,8 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), le16_to_cpu(mbx->mb7))); -done_post_logio_done_work: - lio->ctx.type == SRB_LOGIN_CMD ? - qla2x00_post_async_login_done_work(fcport->vha, fcport, data): - qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); - - lio->ctx.free(sp); +logio_done: + lio->ctx.done(sp); } static void @@ -1084,35 +1070,21 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, { const char func[] = "LOGIO-IOCB"; const char *type; - struct qla_hw_data *ha = vha->hw; fc_port_t *fcport; srb_t *sp; struct srb_logio *lio; - uint16_t data[2]; + uint16_t *data; uint32_t iop[2]; sp = qla2x00_get_sp_from_handle(vha, func, req, logio); if (!sp) return; - type = NULL; lio = sp->ctx; - switch (lio->ctx.type) { - case SRB_LOGIN_CMD: - type = "login"; - break; - case SRB_LOGOUT_CMD: - type = "logout"; - break; - default: - qla_printk(KERN_WARNING, ha, - "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, - lio->ctx.type); - return; - } - del_timer(&lio->ctx.timer); + type = lio->ctx.name; fcport = sp->fcport; + data = lio->data; data[0] = data[1] = 0; if (logio->entry_status) { @@ -1125,7 +1097,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, data[0] = MBS_COMMAND_ERROR; data[1] = lio->flags & SRB_LOGIN_RETRIED ? QLA_LOGIO_LOGIN_RETRIED: 0; - goto done_post_logio_done_work; + goto logio_done; } if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { @@ -1136,7 +1108,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, data[0] = MBS_COMMAND_COMPLETE; if (lio->ctx.type == SRB_LOGOUT_CMD) - goto done_post_logio_done_work; + goto logio_done; iop[0] = le32_to_cpu(logio->io_parameter[0]); if (iop[0] & BIT_4) { @@ -1151,7 +1123,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, if (logio->io_parameter[9] || logio->io_parameter[10]) fcport->supported_classes |= FC_COS_CLASS3; - goto done_post_logio_done_work; + goto logio_done; } iop[0] = le32_to_cpu(logio->io_parameter[0]); @@ -1184,12 +1156,8 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, le32_to_cpu(logio->io_parameter[0]), le32_to_cpu(logio->io_parameter[1]))); -done_post_logio_done_work: - lio->ctx.type == SRB_LOGIN_CMD ? - qla2x00_post_async_login_done_work(fcport->vha, fcport, data): - qla2x00_post_async_logout_done_work(fcport->vha, fcport, data); - - lio->ctx.free(sp); +logio_done: + lio->ctx.done(sp); } /** -- cgit v1.2.3-70-g09d2 From 5ff1d58410ffb160b388d622ef0c6a0411a05559 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 4 May 2010 15:01:26 -0700 Subject: [SCSI] qla2xxx: Limit mailbox command contention for ADISC requests. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 7 ++++ drivers/scsi/qla2xxx/qla_gbl.h | 8 ++++ drivers/scsi/qla2xxx/qla_init.c | 88 ++++++++++++++++++++++++++++++++++++++--- drivers/scsi/qla2xxx/qla_iocb.c | 39 +++++++++++++++++- drivers/scsi/qla2xxx/qla_isr.c | 33 ++++++++-------- drivers/scsi/qla2xxx/qla_os.c | 31 +++++++++++++-- 6 files changed, 178 insertions(+), 28 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b3cf6099600..a491338e1bf 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -219,6 +219,7 @@ typedef struct srb { #define SRB_ELS_CMD_RPT 3 #define SRB_ELS_CMD_HST 4 #define SRB_CT_CMD 5 +#define SRB_ADISC_CMD 6 struct srb_ctx { uint16_t type; @@ -1623,6 +1624,7 @@ typedef struct fc_port { #define FCF_FABRIC_DEVICE BIT_0 #define FCF_LOGIN_NEEDED BIT_1 #define FCF_FCP2_DEVICE BIT_2 +#define FCF_ASYNC_SENT BIT_3 /* No loop ID flag. */ #define FC_NO_LOOP_ID 0x1000 @@ -2156,6 +2158,8 @@ enum qla_work_type { QLA_EVT_ASYNC_LOGIN_DONE, QLA_EVT_ASYNC_LOGOUT, QLA_EVT_ASYNC_LOGOUT_DONE, + QLA_EVT_ASYNC_ADISC, + QLA_EVT_ASYNC_ADISC_DONE, QLA_EVT_UEVENT, }; @@ -2514,6 +2518,9 @@ struct qla_hw_data { dma_addr_t ex_init_cb_dma; struct ex_init_cb_81xx *ex_init_cb; + void *async_pd; + dma_addr_t async_pd_dma; + /* These are used by mailbox operations. */ volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index cff5a4ae762..03be2984190 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -56,10 +56,14 @@ extern void qla84xx_put_chip(struct scsi_qla_host *); extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); +extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *, + uint16_t *); extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); +extern int qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, + uint16_t *); extern fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); @@ -97,6 +101,10 @@ extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *, fc_port_t *, uint16_t *); +extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *, + uint16_t *); +extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *, + fc_port_t *, uint16_t *); extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c3c2c3627a7..4e7a3d5493e 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -119,6 +119,7 @@ qla2x00_async_logio_timeout(srb_t *sp) "scsi(%ld:%x): Async-%s timeout.\n", fcport->vha->host_no, sp->handle, lio->ctx.name)); + fcport->flags &= ~FCF_ASYNC_SENT; if (lio->ctx.type == SRB_LOGIN_CMD) qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); } @@ -220,6 +221,56 @@ done: return rval; } +static void +qla2x00_async_adisc_ctx_done(srb_t *sp) +{ + struct srb_logio *lio = sp->ctx; + + qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport, + lio->data); + lio->ctx.free(sp); +} + +int +qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) +{ + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_logio *lio; + int rval; + + rval = QLA_FUNCTION_FAILED; + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), + ELS_TMO_2_RATOV(ha) + 2); + if (!sp) + goto done; + + lio = sp->ctx; + lio->ctx.type = SRB_ADISC_CMD; + lio->ctx.name = "adisc"; + lio->ctx.timeout = qla2x00_async_logio_timeout; + lio->ctx.done = qla2x00_async_adisc_ctx_done; + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + lio->flags |= SRB_LOGIN_RETRIED; + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-adisc - loop-id=%x portid=%02x%02x%02x.\n", + fcport->vha->host_no, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); + + return rval; + +done_free_sp: + del_timer_sync(&lio->ctx.timer); + lio->ctx.free(sp); +done: + return rval; +} + int qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) @@ -229,15 +280,14 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, switch (data[0]) { case MBS_COMMAND_COMPLETE: if (fcport->flags & FCF_FCP2_DEVICE) { - rval = qla2x00_get_port_database(vha, fcport, BIT_1); - if (rval != QLA_SUCCESS) { - qla2x00_mark_device_lost(vha, fcport, 1, 0); - break; - } + fcport->flags |= FCF_ASYNC_SENT; + qla2x00_post_async_adisc_work(vha, fcport, data); + break; } qla2x00_update_fcport(vha, fcport); break; case MBS_COMMAND_ERROR: + fcport->flags &= ~FCF_ASYNC_SENT; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else @@ -251,6 +301,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->loop_id++; rval = qla2x00_find_new_loop_id(vha, fcport); if (rval != QLA_SUCCESS) { + fcport->flags &= ~FCF_ASYNC_SENT; qla2x00_mark_device_lost(vha, fcport, 1, 0); break; } @@ -268,6 +319,26 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, return QLA_SUCCESS; } +int +qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, + uint16_t *data) +{ + if (data[0] == MBS_COMMAND_COMPLETE) { + qla2x00_update_fcport(vha, fcport); + + return QLA_SUCCESS; + } + + /* Retry login. */ + fcport->flags &= ~FCF_ASYNC_SENT; + if (data[1] & QLA_LOGIO_LOGIN_RETRIED) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + else + qla2x00_mark_device_lost(vha, fcport, 1, 0); + + return QLA_SUCCESS; +} + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -2062,6 +2133,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) if (IS_QLA23XX(ha)) { nv->firmware_options[0] |= BIT_2; nv->firmware_options[0] &= ~BIT_3; + nv->firmware_options[0] &= ~BIT_6; nv->add_firmware_options[1] |= BIT_5 | BIT_4; if (IS_QLA2300(ha)) { @@ -2680,7 +2752,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) PORT_RETRY_TIME; atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * PORT_RETRY_TIME); - fcport->flags &= ~FCF_LOGIN_NEEDED; + fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); qla2x00_iidma_fcport(vha, fcport); @@ -3326,11 +3398,15 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport, retry = 0; if (IS_ALOGIO_CAPABLE(ha)) { + if (fcport->flags & FCF_ASYNC_SENT) + return rval; + fcport->flags |= FCF_ASYNC_SENT; rval = qla2x00_post_async_login_work(vha, fcport, NULL); if (!rval) return rval; } + fcport->flags &= ~FCF_ASYNC_SENT; rval = qla2x00_fabric_login(vha, fcport, next_loopid); if (rval == QLA_SUCCESS) { /* Send an ADISC to FCP2 devices.*/ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d792ae32ed6..8112e41065f 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1053,6 +1053,36 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) /* Implicit: mbx->mbx10 = 0. */ } +static void +qla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio) +{ + logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; + logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC); + logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); + logio->vp_index = sp->fcport->vp_idx; +} + +static void +qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) +{ + struct qla_hw_data *ha = sp->fcport->vha->hw; + + mbx->entry_type = MBX_IOCB_TYPE; + SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); + mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE); + if (HAS_EXTENDED_IDS(ha)) { + mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); + mbx->mb10 = cpu_to_le16(BIT_0); + } else { + mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0); + } + mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma)); + mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma)); + mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma))); + mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma))); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); +} + static void qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { @@ -1185,12 +1215,12 @@ qla2x00_start_sp(srb_t *sp) switch (ctx->type) { case SRB_LOGIN_CMD: IS_FWI2_CAPABLE(ha) ? - qla24xx_login_iocb(sp, pkt): + qla24xx_login_iocb(sp, pkt) : qla2x00_login_iocb(sp, pkt); break; case SRB_LOGOUT_CMD: IS_FWI2_CAPABLE(ha) ? - qla24xx_logout_iocb(sp, pkt): + qla24xx_logout_iocb(sp, pkt) : qla2x00_logout_iocb(sp, pkt); break; case SRB_ELS_CMD_RPT: @@ -1200,6 +1230,11 @@ qla2x00_start_sp(srb_t *sp) case SRB_CT_CMD: qla24xx_ct_iocb(sp, pkt); break; + case SRB_ADISC_CMD: + IS_FWI2_CAPABLE(ha) ? + qla24xx_adisc_iocb(sp, pkt) : + qla2x00_adisc_iocb(sp, pkt); + break; default: break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 037bc41eef5..a1968eb5e9c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -899,6 +899,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, srb_t *sp; struct srb_logio *lio; uint16_t *data; + uint16_t status; sp = qla2x00_get_sp_from_handle(vha, func, req, mbx); if (!sp) @@ -910,7 +911,9 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, fcport = sp->fcport; data = lio->data; - data[0] = data[1] = 0; + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED : 0; if (mbx->entry_status) { DEBUG2(printk(KERN_WARNING "scsi(%ld:%x): Async-%s error entry - entry-status=%x " @@ -921,26 +924,27 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(mbx->status_flags))); DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx))); - data[0] = MBS_COMMAND_ERROR; - data[1] = lio->flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED: 0; goto logio_done; } - if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { + status = le16_to_cpu(mbx->status); + if (status == 0x30 && lio->ctx.type == SRB_LOGIN_CMD && + le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) + status = 0; + if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { DEBUG2(printk(KERN_DEBUG "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n", fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->mb1))); data[0] = MBS_COMMAND_COMPLETE; - if (lio->ctx.type == SRB_LOGIN_CMD) + if (lio->ctx.type == SRB_LOGIN_CMD) { fcport->port_type = FCT_TARGET; if (le16_to_cpu(mbx->mb1) & BIT_0) fcport->port_type = FCT_INITIATOR; if (le16_to_cpu(mbx->mb1) & BIT_1) fcport->flags |= FCF_FCP2_DEVICE; - + } goto logio_done; } @@ -953,15 +957,13 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, break; default: data[0] = MBS_COMMAND_ERROR; - data[1] = lio->flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED: 0; break; } DEBUG2(printk(KERN_WARNING "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x " "mb6=%x mb7=%x.\n", - fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status), + fcport->vha->host_no, sp->handle, type, status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), le16_to_cpu(mbx->mb7))); @@ -1086,7 +1088,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, fcport = sp->fcport; data = lio->data; - data[0] = data[1] = 0; + data[0] = MBS_COMMAND_ERROR; + data[1] = lio->flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED : 0; if (logio->entry_status) { DEBUG2(printk(KERN_WARNING "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", @@ -1094,9 +1098,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, logio->entry_status)); DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio))); - data[0] = MBS_COMMAND_ERROR; - data[1] = lio->flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED: 0; goto logio_done; } @@ -1107,7 +1108,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, le32_to_cpu(logio->io_parameter[0]))); data[0] = MBS_COMMAND_COMPLETE; - if (lio->ctx.type == SRB_LOGOUT_CMD) + if (lio->ctx.type != SRB_LOGIN_CMD) goto logio_done; iop[0] = le32_to_cpu(logio->io_parameter[0]); @@ -1144,8 +1145,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, /* Fall through. */ default: data[0] = MBS_COMMAND_ERROR; - data[1] = lio->flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED: 0; break; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 10c14af2235..2e083c0d921 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2639,9 +2639,19 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, INIT_LIST_HEAD(&ha->gbl_dsd_list); + /* Get consistent memory allocated for Async Port-Database. */ + if (!IS_FWI2_CAPABLE(ha)) { + ha->async_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, + &ha->async_pd_dma); + if (!ha->async_pd) + goto fail_async_pd; + } + INIT_LIST_HEAD(&ha->vp_list); return 1; +fail_async_pd: + dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); fail_ex_init_cb: kfree(ha->npiv_info); fail_npiv_info: @@ -2757,6 +2767,9 @@ qla2x00_mem_free(struct qla_hw_data *ha) dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); + if (ha->async_pd) + dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); + if (ha->s_dma_pool) dma_pool_destroy(ha->s_dma_pool); @@ -2809,6 +2822,8 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->init_cb_dma = 0; ha->ex_init_cb = NULL; ha->ex_init_cb_dma = 0; + ha->async_pd = NULL; + ha->async_pd_dma = 0; ha->s_dma_pool = NULL; ha->dl_dma_pool = NULL; @@ -2935,6 +2950,8 @@ 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); +qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); +qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE); int qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code) @@ -3004,6 +3021,14 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla2x00_async_logout_done(vha, e->u.logio.fcport, e->u.logio.data); break; + case QLA_EVT_ASYNC_ADISC: + qla2x00_async_adisc(vha, e->u.logio.fcport, + e->u.logio.data); + break; + case QLA_EVT_ASYNC_ADISC_DONE: + qla2x00_async_adisc_done(vha, e->u.logio.fcport, + e->u.logio.data); + break; case QLA_EVT_UEVENT: qla2x00_uevent_emit(vha, e->u.uevent.code); break; @@ -3029,9 +3054,8 @@ void qla2x00_relogin(struct scsi_qla_host *vha) * If the port is not ONLINE then try to login * to it if we haven't run out of retries. */ - if (atomic_read(&fcport->state) != - FCS_ONLINE && fcport->login_retry) { - + if (atomic_read(&fcport->state) != FCS_ONLINE && + fcport->login_retry && !(fcport->flags & FCF_ASYNC_SENT)) { fcport->login_retry--; if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_FCP2_DEVICE) @@ -3042,6 +3066,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha) fcport->d_id.b.al_pa); if (IS_ALOGIO_CAPABLE(ha)) { + fcport->flags |= FCF_ASYNC_SENT; data[0] = 0; data[1] = QLA_LOGIO_LOGIN_RETRIED; status = qla2x00_post_async_login_work( -- cgit v1.2.3-70-g09d2 From b7d2280c153b33fc60f1a89406d2329137a8b61c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 4 May 2010 15:01:27 -0700 Subject: [SCSI] qla2xxx: Cleanup FCP-command-status processing debug statements. Migrate to a consistent set of debug entries during status-IOCB handling: * group CS_TIMEOUT handling with CS_PORT_UNAVAILABLE and the like (more regrouping of common behaviour). * drop CS_DATA_OVERRUN handling as it now falls into the 'default' case (still returns DID_ERROR). * consolidate CS_RESET and CS_ABORTED handling, as we the only functional difference was a printk() (still returns DID_RESET). * dropped all the earlier inconsistent [qla_]printk()s sprinkled throught the needlessly large case-statement. Failure case I/Os are now logged with a 'standard' format: so, for example a dropped-frame is logged as: qla2xxx 0000:13:00.0: scsi(16:0:0) Dropped frame(s) detected (4000 of 4000 bytes). qla2xxx 0000:13:00.0: scsi(16:0:0) FCP command status: 0x15-0x18 (70018) \ oxid=78 ser=76 cdb=280000 len=4000 rsp_info=0 resid=0 fw_resid=4000 which should now convey all relevant information. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 192 ++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 129 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a1968eb5e9c..b92f9a6ee4f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1283,6 +1283,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) struct sts_entry_24xx *sts24; uint16_t comp_status; uint16_t scsi_status; + uint16_t ox_id; uint8_t lscsi_status; int32_t resid; uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len; @@ -1291,6 +1292,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) uint32_t handle; uint16_t que; struct req_que *req; + int logit = 1; sts = (sts_entry_t *) pkt; sts24 = (struct sts_entry_24xx *) pkt; @@ -1320,9 +1322,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) sp = NULL; if (sp == NULL) { - DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n", - vha->host_no)); - qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n"); + qla_printk(KERN_WARNING, ha, + "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no, + sts->handle); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); @@ -1330,10 +1332,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } cp = sp->cmd; if (cp == NULL) { - DEBUG2(printk("scsi(%ld): Command already returned back to OS " - "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp)); qla_printk(KERN_WARNING, ha, - "Command is NULL: already returned to OS (sp=%p)\n", sp); + "scsi(%ld): Command already returned (0x%x/%p).\n", + vha->host_no, sts->handle, sp); return; } @@ -1342,6 +1343,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) fcport = sp->fcport; + ox_id = 0; sense_len = rsp_info_len = resid_len = fw_resid_len = 0; if (IS_FWI2_CAPABLE(ha)) { if (scsi_status & SS_SENSE_LEN_VALID) @@ -1355,6 +1357,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) rsp_info = sts24->data; sense_data = sts24->data; host_to_fcp_swap(sts24->data, sizeof(sts24->data)); + ox_id = le16_to_cpu(sts24->ox_id); } else { if (scsi_status & SS_SENSE_LEN_VALID) sense_len = le16_to_cpu(sts->req_sense_length); @@ -1371,17 +1374,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (IS_FWI2_CAPABLE(ha)) sense_data += rsp_info_len; if (rsp_info_len > 3 && rsp_info[3]) { - DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol " - "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..." - "retrying command\n", vha->host_no, - cp->device->channel, cp->device->id, - cp->device->lun, rsp_info_len, rsp_info[0], - rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4], - rsp_info[5], rsp_info[6], rsp_info[7])); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d): FCP I/O protocol failure " + "(0x%x/0x%x).\n", vha->host_no, cp->device->id, + cp->device->lun, rsp_info_len, rsp_info[3])); cp->result = DID_BUS_BUSY << 16; - qla2x00_sp_compl(ha, sp); - return; + goto out; } } @@ -1408,12 +1407,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) ((unsigned)(scsi_bufflen(cp) - resid) < cp->underflow)) { qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d:%d): Mid-layer underflow " - "detected (%x of %x bytes)...returning " - "error status.\n", vha->host_no, - cp->device->channel, cp->device->id, - cp->device->lun, resid, - scsi_bufflen(cp)); + "scsi(%ld:%d:%d): Mid-layer underflow " + "detected (0x%x of 0x%x bytes).\n", + vha->host_no, cp->device->id, + cp->device->lun, resid, scsi_bufflen(cp)); cp->result = DID_ERROR << 16; break; @@ -1422,12 +1419,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->result = DID_OK << 16 | lscsi_status; if (lscsi_status == SAM_STAT_TASK_SET_FULL) { - DEBUG2(printk(KERN_INFO - "scsi(%ld): QUEUE FULL status detected " - "0x%x-0x%x.\n", vha->host_no, comp_status, - scsi_status)); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d) QUEUE FULL detected.\n", + vha->host_no, cp->device->id, cp->device->lun)); break; } + logit = 0; if (lscsi_status != SS_CHECK_CONDITION) break; @@ -1439,23 +1436,14 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) break; case CS_DATA_UNDERRUN: - DEBUG2(printk(KERN_INFO - "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. " - "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n", - vha->host_no, cp->device->id, cp->device->lun, comp_status, - scsi_status, resid_len, fw_resid_len, cp->cmnd[0], - cp->underflow)); - /* Use F/W calculated residual length. */ resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len; scsi_set_resid(cp, resid); if (scsi_status & SS_RESIDUAL_UNDER) { if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) { - DEBUG2(printk( - "scsi(%ld:%d:%d:%d) Dropped frame(s) " - "detected (%x of %x bytes)...residual " - "length mismatch...retrying command.\n", - vha->host_no, cp->device->channel, + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d) Dropped frame(s) detected " + "(0x%x of 0x%x bytes).\n", vha->host_no, cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); @@ -1467,21 +1455,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) ((unsigned)(scsi_bufflen(cp) - resid) < cp->underflow)) { qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d:%d): Mid-layer underflow " - "detected (%x of %x bytes)...returning " - "error status.\n", vha->host_no, - cp->device->channel, cp->device->id, + "scsi(%ld:%d:%d): Mid-layer underflow " + "detected (0x%x of 0x%x bytes).\n", + vha->host_no, cp->device->id, cp->device->lun, resid, scsi_bufflen(cp)); cp->result = DID_ERROR << 16; break; } } else if (!lscsi_status) { - DEBUG2(printk( - "scsi(%ld:%d:%d:%d) Dropped frame(s) detected " - "(%x of %x bytes)...firmware reported underrun..." - "retrying command.\n", vha->host_no, - cp->device->channel, cp->device->id, + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x " + "of 0x%x bytes).\n", vha->host_no, cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); cp->result = DID_ERROR << 16; @@ -1489,6 +1474,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } cp->result = DID_OK << 16 | lscsi_status; + logit = 0; /* * Check to see if SCSI Status is non zero. If so report SCSI @@ -1496,10 +1482,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) */ if (lscsi_status != 0) { if (lscsi_status == SAM_STAT_TASK_SET_FULL) { - DEBUG2(printk(KERN_INFO - "scsi(%ld): QUEUE FULL status detected " - "0x%x-0x%x.\n", vha->host_no, comp_status, - scsi_status)); + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d) QUEUE FULL detected.\n", + vha->host_no, cp->device->id, + cp->device->lun)); + logit = 1; break; } if (lscsi_status != SS_CHECK_CONDITION) @@ -1513,109 +1500,56 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } break; - case CS_DATA_OVERRUN: - DEBUG2(printk(KERN_INFO - "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n", - vha->host_no, cp->device->id, cp->device->lun, comp_status, - scsi_status)); - DEBUG2(printk(KERN_INFO - "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3], - cp->cmnd[4], cp->cmnd[5])); - DEBUG2(printk(KERN_INFO - "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR " - "status!\n", - cp->serial_number, scsi_bufflen(cp), resid_len)); - - cp->result = DID_ERROR << 16; - break; - case CS_PORT_LOGGED_OUT: case CS_PORT_CONFIG_CHG: case CS_PORT_BUSY: case CS_INCOMPLETE: case CS_PORT_UNAVAILABLE: - /* - * If the port is in Target Down state, return all IOs for this - * Target with DID_NO_CONNECT ELSE Queue the IOs in the - * retry_queue. - */ - DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down " - "pid=%ld, compl status=0x%x, port state=0x%x\n", - vha->host_no, cp->device->id, cp->device->lun, - cp->serial_number, comp_status, - atomic_read(&fcport->state))); - + case CS_TIMEOUT: /* * We are going to have the fc class block the rport * while we try to recover so instruct the mid layer * to requeue until the class decides how to handle this. */ cp->result = DID_TRANSPORT_DISRUPTED << 16; + + if (comp_status == CS_TIMEOUT) { + if (IS_FWI2_CAPABLE(ha)) + break; + else if ((le16_to_cpu(sts->status_flags) & + SF_LOGOUT_SENT) == 0) + break; + } + + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d) Port down status: port-state=0x%x\n", + vha->host_no, cp->device->id, cp->device->lun, + atomic_read(&fcport->state))); + if (atomic_read(&fcport->state) == FCS_ONLINE) qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1); break; case CS_RESET: - DEBUG2(printk(KERN_INFO - "scsi(%ld): RESET status detected 0x%x-0x%x.\n", - vha->host_no, comp_status, scsi_status)); - - cp->result = DID_RESET << 16; - break; - case CS_ABORTED: - /* - * hv2.19.12 - DID_ABORT does not retry the request if we - * aborted this request then abort otherwise it must be a - * reset. - */ - DEBUG2(printk(KERN_INFO - "scsi(%ld): ABORT status detected 0x%x-0x%x.\n", - vha->host_no, comp_status, scsi_status)); - cp->result = DID_RESET << 16; break; - - case CS_TIMEOUT: - /* - * We are going to have the fc class block the rport - * while we try to recover so instruct the mid layer - * to requeue until the class decides how to handle this. - */ - cp->result = DID_TRANSPORT_DISRUPTED << 16; - - if (IS_FWI2_CAPABLE(ha)) { - DEBUG2(printk(KERN_INFO - "scsi(%ld:%d:%d:%d): TIMEOUT status detected " - "0x%x-0x%x\n", vha->host_no, cp->device->channel, - cp->device->id, cp->device->lun, comp_status, - scsi_status)); - break; - } - DEBUG2(printk(KERN_INFO - "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x " - "sflags=%x.\n", vha->host_no, cp->device->channel, - cp->device->id, cp->device->lun, comp_status, scsi_status, - le16_to_cpu(sts->status_flags))); - - /* Check to see if logout occurred. */ - if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT)) - qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1); - break; - default: - DEBUG3(printk("scsi(%ld): Error detected (unknown status) " - "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status)); - qla_printk(KERN_INFO, ha, - "Unknown status detected 0x%x-0x%x.\n", - comp_status, scsi_status); - cp->result = DID_ERROR << 16; break; } - /* Place command on done queue. */ +out: + if (logit) + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) " + "oxid=0x%x ser=0x%lx cdb=%02x%02x%02x len=0x%x " + "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no, + cp->device->id, cp->device->lun, comp_status, scsi_status, + cp->result, ox_id, cp->serial_number, cp->cmnd[0], + cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, + resid_len, fw_resid_len)); + if (rsp->status_srb == NULL) qla2x00_sp_compl(ha, sp); } -- cgit v1.2.3-70-g09d2 From 4916392b56921b4aaaeaca3ef492135f42fbb5f2 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Tue, 4 May 2010 15:01:28 -0700 Subject: [SCSI] qla2xxx: Provide common framework for BSG and IOCB commands. Currently, BSG and IOCB/Logio commands have a different framework (srb structs). The purpose of this effort is to consolidate them into a generalized framework for these as well as other asynchronous operations in the future. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 28 ++++----- drivers/scsi/qla2xxx/qla_def.h | 48 +++++++------- drivers/scsi/qla2xxx/qla_gbl.h | 6 +- drivers/scsi/qla2xxx/qla_init.c | 135 +++++++++++++++++++++++----------------- drivers/scsi/qla2xxx/qla_iocb.c | 24 ++++--- drivers/scsi/qla2xxx/qla_isr.c | 50 ++++++++------- drivers/scsi/qla2xxx/qla_os.c | 13 ++-- 7 files changed, 162 insertions(+), 142 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 21e5bcd4bb5..951db816ee4 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -16,7 +16,7 @@ qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size) { srb_t *sp; struct qla_hw_data *ha = vha->hw; - struct srb_bsg_ctx *ctx; + struct srb_ctx *ctx; sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); if (!sp) @@ -208,7 +208,7 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) int req_sg_cnt, rsp_sg_cnt; int rval = (DRIVER_ERROR << 16); uint16_t nextlid = 0; - struct srb_bsg *els; + struct srb_ctx *els; /* Multiple SG's are not supported for ELS requests */ if (bsg_job->request_payload.sg_cnt > 1 || @@ -307,17 +307,17 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) } /* Alloc SRB structure */ - sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); + sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx)); if (!sp) { rval = -ENOMEM; goto done_unmap_sg; } els = sp->ctx; - els->ctx.type = + els->type = (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); - els->bsg_job = bsg_job; + els->u.bsg_job = bsg_job; DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " @@ -361,7 +361,7 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) uint16_t loop_id; struct fc_port *fcport; char *type = "FC_BSG_HST_CT"; - struct srb_bsg *ct; + struct srb_ctx *ct; /* pass through is supported only for ISP 4Gb or higher */ if (!IS_FWI2_CAPABLE(ha)) { @@ -442,15 +442,15 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) fcport->loop_id = loop_id; /* Alloc SRB structure */ - sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg)); + sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx)); if (!sp) { rval = -ENOMEM; goto done_free_fcport; } ct = sp->ctx; - ct->ctx.type = SRB_CT_CMD; - ct->bsg_job = bsg_job; + ct->type = SRB_CT_CMD; + ct->u.bsg_job = bsg_job; DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x " @@ -1155,7 +1155,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) int cnt, que; unsigned long flags; struct req_que *req; - struct srb_bsg *sp_bsg; + struct srb_ctx *sp_bsg; /* find the bsg job from the active list of commands */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1167,11 +1167,11 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = req->outstanding_cmds[cnt]; if (sp) { - sp_bsg = (struct srb_bsg *)sp->ctx; + sp_bsg = sp->ctx; - if (((sp_bsg->ctx.type == SRB_CT_CMD) || - (sp_bsg->ctx.type == SRB_ELS_CMD_HST)) - && (sp_bsg->bsg_job == bsg_job)) { + if (((sp_bsg->type == SRB_CT_CMD) || + (sp_bsg->type == SRB_ELS_CMD_HST)) + && (sp_bsg->u.bsg_job == bsg_job)) { if (ha->isp_ops->abort_command(sp)) { DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld): mbx " diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index a491338e1bf..08f5fd5359d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -214,16 +214,16 @@ typedef struct srb { /* * SRB extensions. */ -#define SRB_LOGIN_CMD 1 -#define SRB_LOGOUT_CMD 2 -#define SRB_ELS_CMD_RPT 3 -#define SRB_ELS_CMD_HST 4 -#define SRB_CT_CMD 5 -#define SRB_ADISC_CMD 6 - -struct srb_ctx { - uint16_t type; - char *name; +struct srb_iocb { + union { + struct { + uint16_t flags; +#define SRB_LOGIN_RETRIED BIT_0 +#define SRB_LOGIN_COND_PLOGI BIT_1 +#define SRB_LOGIN_SKIP_PRLI BIT_2 + uint16_t data[2]; + } logio; + } u; struct timer_list timer; @@ -232,23 +232,21 @@ struct srb_ctx { void (*timeout)(srb_t *); }; -struct srb_logio { - struct srb_ctx ctx; - -#define SRB_LOGIN_RETRIED BIT_0 -#define SRB_LOGIN_COND_PLOGI BIT_1 -#define SRB_LOGIN_SKIP_PRLI BIT_2 - uint16_t flags; - uint16_t data[2]; -}; +/* Values for srb_ctx type */ +#define SRB_LOGIN_CMD 1 +#define SRB_LOGOUT_CMD 2 +#define SRB_ELS_CMD_RPT 3 +#define SRB_ELS_CMD_HST 4 +#define SRB_CT_CMD 5 +#define SRB_ADISC_CMD 6 -struct srb_bsg_ctx { +struct srb_ctx { uint16_t type; -}; - -struct srb_bsg { - struct srb_bsg_ctx ctx; - struct fc_bsg_job *bsg_job; + char *name; + union { + struct srb_iocb *iocb_cmd; + struct fc_bsg_job *bsg_job; + } u; }; struct msg_echo_lb { diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 03be2984190..408e5f0a53c 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -58,11 +58,11 @@ extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *, extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, +extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, +extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern int qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, +extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern fc_port_t * diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4e7a3d5493e..72b4ef27015 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -48,6 +48,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data) { srb_t *sp = (srb_t *)__data; struct srb_ctx *ctx; + struct srb_iocb *iocb; fc_port_t *fcport = sp->fcport; struct qla_hw_data *ha = fcport->vha->hw; struct req_que *req; @@ -57,17 +58,21 @@ qla2x00_ctx_sp_timeout(unsigned long __data) req = ha->req_q_map[0]; req->outstanding_cmds[sp->handle] = NULL; ctx = sp->ctx; - ctx->timeout(sp); + iocb = ctx->u.iocb_cmd; + iocb->timeout(sp); spin_unlock_irqrestore(&ha->hardware_lock, flags); - ctx->free(sp); + iocb->free(sp); } void qla2x00_ctx_sp_free(srb_t *sp) { struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *iocb = ctx->u.iocb_cmd; + del_timer_sync(&iocb->timer); + kfree(iocb); kfree(ctx); mempool_free(sp, sp->fcport->vha->hw->srb_mempool); } @@ -79,6 +84,7 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, srb_t *sp; struct qla_hw_data *ha = vha->hw; struct srb_ctx *ctx; + struct srb_iocb *iocb; sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); if (!sp) @@ -86,21 +92,30 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, ctx = kzalloc(size, GFP_KERNEL); if (!ctx) { mempool_free(sp, ha->srb_mempool); + sp = NULL; + goto done; + } + iocb = kzalloc(sizeof(struct srb_iocb), GFP_KERNEL); + if (!iocb) { + mempool_free(sp, ha->srb_mempool); + sp = NULL; + kfree(ctx); goto done; } memset(sp, 0, sizeof(*sp)); sp->fcport = fcport; sp->ctx = ctx; - ctx->free = qla2x00_ctx_sp_free; + ctx->u.iocb_cmd = iocb; + iocb->free = qla2x00_ctx_sp_free; - init_timer(&ctx->timer); + init_timer(&iocb->timer); if (!tmo) goto done; - ctx->timer.expires = jiffies + tmo * HZ; - ctx->timer.data = (unsigned long)sp; - ctx->timer.function = qla2x00_ctx_sp_timeout; - add_timer(&ctx->timer); + iocb->timer.expires = jiffies + tmo * HZ; + iocb->timer.data = (unsigned long)sp; + iocb->timer.function = qla2x00_ctx_sp_timeout; + add_timer(&iocb->timer); done: return sp; } @@ -113,25 +128,26 @@ static void qla2x00_async_logio_timeout(srb_t *sp) { fc_port_t *fcport = sp->fcport; - struct srb_logio *lio = sp->ctx; + struct srb_ctx *ctx = sp->ctx; DEBUG2(printk(KERN_WARNING "scsi(%ld:%x): Async-%s timeout.\n", - fcport->vha->host_no, sp->handle, lio->ctx.name)); + fcport->vha->host_no, sp->handle, ctx->name)); fcport->flags &= ~FCF_ASYNC_SENT; - if (lio->ctx.type == SRB_LOGIN_CMD) + if (ctx->type == SRB_LOGIN_CMD) qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); } static void qla2x00_async_login_ctx_done(srb_t *sp) { - struct srb_logio *lio = sp->ctx; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *lio = ctx->u.iocb_cmd; qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport, - lio->data); - lio->ctx.free(sp); + lio->u.logio.data); + lio->free(sp); } int @@ -140,23 +156,25 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, { struct qla_hw_data *ha = vha->hw; srb_t *sp; - struct srb_logio *lio; + struct srb_ctx *ctx; + struct srb_iocb *lio; int rval; rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), ELS_TMO_2_RATOV(ha) + 2); if (!sp) goto done; - lio = sp->ctx; - lio->ctx.type = SRB_LOGIN_CMD; - lio->ctx.name = "login"; - lio->ctx.timeout = qla2x00_async_logio_timeout; - lio->ctx.done = qla2x00_async_login_ctx_done; - lio->flags |= SRB_LOGIN_COND_PLOGI; + ctx = sp->ctx; + ctx->type = SRB_LOGIN_CMD; + ctx->name = "login"; + lio = ctx->u.iocb_cmd; + lio->timeout = qla2x00_async_logio_timeout; + lio->done = qla2x00_async_login_ctx_done; + lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - lio->flags |= SRB_LOGIN_RETRIED; + lio->u.logio.flags |= SRB_LOGIN_RETRIED; rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; @@ -169,8 +187,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, return rval; done_free_sp: - del_timer_sync(&lio->ctx.timer); - lio->ctx.free(sp); + lio->free(sp); done: return rval; } @@ -178,11 +195,12 @@ done: static void qla2x00_async_logout_ctx_done(srb_t *sp) { - struct srb_logio *lio = sp->ctx; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *lio = ctx->u.iocb_cmd; qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport, - lio->data); - lio->ctx.free(sp); + lio->u.logio.data); + lio->free(sp); } int @@ -190,20 +208,22 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) { struct qla_hw_data *ha = vha->hw; srb_t *sp; - struct srb_logio *lio; + struct srb_ctx *ctx; + struct srb_iocb *lio; int rval; rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), ELS_TMO_2_RATOV(ha) + 2); if (!sp) goto done; - lio = sp->ctx; - lio->ctx.type = SRB_LOGOUT_CMD; - lio->ctx.name = "logout"; - lio->ctx.timeout = qla2x00_async_logio_timeout; - lio->ctx.done = qla2x00_async_logout_ctx_done; + ctx = sp->ctx; + ctx->type = SRB_LOGOUT_CMD; + ctx->name = "logout"; + lio = ctx->u.iocb_cmd; + lio->timeout = qla2x00_async_logio_timeout; + lio->done = qla2x00_async_logout_ctx_done; rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; @@ -215,8 +235,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) return rval; done_free_sp: - del_timer_sync(&lio->ctx.timer); - lio->ctx.free(sp); + lio->free(sp); done: return rval; } @@ -224,11 +243,12 @@ done: static void qla2x00_async_adisc_ctx_done(srb_t *sp) { - struct srb_logio *lio = sp->ctx; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *lio = ctx->u.iocb_cmd; qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport, - lio->data); - lio->ctx.free(sp); + lio->u.logio.data); + lio->free(sp); } int @@ -237,22 +257,24 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, { struct qla_hw_data *ha = vha->hw; srb_t *sp; - struct srb_logio *lio; + struct srb_ctx *ctx; + struct srb_iocb *lio; int rval; rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio), + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), ELS_TMO_2_RATOV(ha) + 2); if (!sp) goto done; - lio = sp->ctx; - lio->ctx.type = SRB_ADISC_CMD; - lio->ctx.name = "adisc"; - lio->ctx.timeout = qla2x00_async_logio_timeout; - lio->ctx.done = qla2x00_async_adisc_ctx_done; + ctx = sp->ctx; + ctx->type = SRB_ADISC_CMD; + ctx->name = "adisc"; + lio = ctx->u.iocb_cmd; + lio->timeout = qla2x00_async_logio_timeout; + lio->done = qla2x00_async_adisc_ctx_done; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - lio->flags |= SRB_LOGIN_RETRIED; + lio->u.logio.flags |= SRB_LOGIN_RETRIED; rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; @@ -265,13 +287,12 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, return rval; done_free_sp: - del_timer_sync(&lio->ctx.timer); - lio->ctx.free(sp); + lio->free(sp); done: return rval; } -int +void qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { @@ -308,25 +329,25 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, qla2x00_post_async_login_work(vha, fcport, NULL); break; } - return QLA_SUCCESS; + return; } -int +void qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { qla2x00_mark_device_lost(vha, fcport, 1, 0); - return QLA_SUCCESS; + return; } -int +void qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { if (data[0] == MBS_COMMAND_COMPLETE) { qla2x00_update_fcport(vha, fcport); - return QLA_SUCCESS; + return; } /* Retry login. */ @@ -336,7 +357,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, else qla2x00_mark_device_lost(vha, fcport, 1, 0); - return QLA_SUCCESS; + return; } /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8112e41065f..8861b88319f 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -983,13 +983,14 @@ qla2x00_start_iocbs(srb_t *sp) static void qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) { - struct srb_logio *lio = sp->ctx; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *lio = ctx->u.iocb_cmd; logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); - if (lio->flags & SRB_LOGIN_COND_PLOGI) + if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); - if (lio->flags & SRB_LOGIN_SKIP_PRLI) + if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); logio->port_id[0] = sp->fcport->d_id.b.al_pa; @@ -1002,14 +1003,15 @@ static void qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) { struct qla_hw_data *ha = sp->fcport->vha->hw; - struct srb_logio *lio = sp->ctx; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *lio = ctx->u.iocb_cmd; uint16_t opts; mbx->entry_type = MBX_IOCB_TYPE;; SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); - opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0; - opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0; + opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0; + opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0; if (HAS_EXTENDED_IDS(ha)) { mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); mbx->mb10 = cpu_to_le16(opts); @@ -1086,7 +1088,7 @@ qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) static void qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { - struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; + struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job; els_iocb->entry_type = ELS_IOCB_TYPE; els_iocb->entry_count = 1; @@ -1099,8 +1101,10 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->sof_type = EST_SOFI3; els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); - els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ? - bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code; + els_iocb->opcode = + (((struct srb_ctx *)sp->ctx)->type == SRB_ELS_CMD_RPT) ? + bsg_job->request->rqst_data.r_els.els_code : + bsg_job->request->rqst_data.h_els.command_code; els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; els_iocb->port_id[1] = sp->fcport->d_id.b.area; els_iocb->port_id[2] = sp->fcport->d_id.b.domain; @@ -1134,7 +1138,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) int index; uint16_t tot_dsds; scsi_qla_host_t *vha = sp->fcport->vha; - struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job; + struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job; int loop_iterartion = 0; int cont_iocb_prsnt = 0; int entry_count = 1; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b92f9a6ee4f..166bb2045fd 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -897,7 +897,8 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, const char *type; fc_port_t *fcport; srb_t *sp; - struct srb_logio *lio; + struct srb_iocb *lio; + struct srb_ctx *ctx; uint16_t *data; uint16_t status; @@ -905,14 +906,14 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, if (!sp) return; - lio = sp->ctx; - del_timer(&lio->ctx.timer); - type = lio->ctx.name; + ctx = sp->ctx; + lio = ctx->u.iocb_cmd; + type = ctx->name; fcport = sp->fcport; - data = lio->data; + data = lio->u.logio.data; data[0] = MBS_COMMAND_ERROR; - data[1] = lio->flags & SRB_LOGIN_RETRIED ? + data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? QLA_LOGIO_LOGIN_RETRIED : 0; if (mbx->entry_status) { DEBUG2(printk(KERN_WARNING @@ -928,7 +929,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, } status = le16_to_cpu(mbx->status); - if (status == 0x30 && lio->ctx.type == SRB_LOGIN_CMD && + if (status == 0x30 && ctx->type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) status = 0; if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { @@ -938,7 +939,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(mbx->mb1))); data[0] = MBS_COMMAND_COMPLETE; - if (lio->ctx.type == SRB_LOGIN_CMD) { + if (ctx->type == SRB_LOGIN_CMD) { fcport->port_type = FCT_TARGET; if (le16_to_cpu(mbx->mb1) & BIT_0) fcport->port_type = FCT_INITIATOR; @@ -969,7 +970,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, le16_to_cpu(mbx->mb7))); logio_done: - lio->ctx.done(sp); + lio->done(sp); } static void @@ -980,7 +981,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, const char *type; struct qla_hw_data *ha = vha->hw; srb_t *sp; - struct srb_bsg *sp_bsg; + struct srb_ctx *sp_bsg; struct fc_bsg_job *bsg_job; uint16_t comp_status; uint32_t fw_status[3]; @@ -989,11 +990,11 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (!sp) return; - sp_bsg = (struct srb_bsg*)sp->ctx; - bsg_job = sp_bsg->bsg_job; + sp_bsg = sp->ctx; + bsg_job = sp_bsg->u.bsg_job; type = NULL; - switch (sp_bsg->ctx.type) { + switch (sp_bsg->type) { case SRB_ELS_CMD_RPT: case SRB_ELS_CMD_HST: type = "els"; @@ -1004,7 +1005,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, default: qla_printk(KERN_WARNING, ha, "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, - sp_bsg->ctx.type); + sp_bsg->type); return; } @@ -1058,8 +1059,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) || - (sp_bsg->ctx.type == SRB_CT_CMD)) + if ((sp_bsg->type == SRB_ELS_CMD_HST) || + (sp_bsg->type == SRB_CT_CMD)) kfree(sp->fcport); kfree(sp->ctx); mempool_free(sp, ha->srb_mempool); @@ -1074,7 +1075,8 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, const char *type; fc_port_t *fcport; srb_t *sp; - struct srb_logio *lio; + struct srb_iocb *lio; + struct srb_ctx *ctx; uint16_t *data; uint32_t iop[2]; @@ -1082,14 +1084,14 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, if (!sp) return; - lio = sp->ctx; - del_timer(&lio->ctx.timer); - type = lio->ctx.name; + ctx = sp->ctx; + lio = ctx->u.iocb_cmd; + type = ctx->name; fcport = sp->fcport; - data = lio->data; + data = lio->u.logio.data; data[0] = MBS_COMMAND_ERROR; - data[1] = lio->flags & SRB_LOGIN_RETRIED ? + data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? QLA_LOGIO_LOGIN_RETRIED : 0; if (logio->entry_status) { DEBUG2(printk(KERN_WARNING @@ -1108,7 +1110,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, le32_to_cpu(logio->io_parameter[0]))); data[0] = MBS_COMMAND_COMPLETE; - if (lio->ctx.type != SRB_LOGIN_CMD) + if (ctx->type != SRB_LOGIN_CMD) goto logio_done; iop[0] = le32_to_cpu(logio->io_parameter[0]); @@ -1156,7 +1158,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, le32_to_cpu(logio->io_parameter[1]))); logio_done: - lio->ctx.done(sp); + lio->done(sp); } /** diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2e083c0d921..70651f9fa65 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1191,24 +1191,19 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) ctx = sp->ctx; if (ctx->type == SRB_LOGIN_CMD || ctx->type == SRB_LOGOUT_CMD) { - del_timer_sync(&ctx->timer); - ctx->free(sp); + ctx->u.iocb_cmd->free(sp); } else { - struct srb_bsg *sp_bsg = - (struct srb_bsg *)sp->ctx; struct fc_bsg_job *bsg_job = - sp_bsg->bsg_job; - + ctx->u.bsg_job; if (bsg_job->request->msgcode == FC_BSG_HST_CT) kfree(sp->fcport); bsg_job->req->errors = 0; bsg_job->reply->result = res; - bsg_job->job_done( - sp_bsg->bsg_job); + bsg_job->job_done(bsg_job); kfree(sp->ctx); mempool_free(sp, - ha->srb_mempool); + ha->srb_mempool); } } } -- cgit v1.2.3-70-g09d2 From 3822263eb1e74821ad1ae886ddd2184ae9395ff7 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Tue, 4 May 2010 15:01:29 -0700 Subject: [SCSI] qla2xxx: Support for asynchronous TM and Marker IOCBs. Currently we can only issue the task management (TM) commands via the mailbox mechanism. This is a limitation, since only one mailbox command can be issued at a time. The purpose of this effort is to provide support for issuing and processing the respose to TM and Marker IOCBs asynchronously. Towards achieving this, the consolidated srb architecture that is currently used for BSG and IOCB/Logio commands has been enhanced and used. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 4 ++ drivers/scsi/qla2xxx/qla_def.h | 22 ++++++ drivers/scsi/qla2xxx/qla_gbl.h | 7 ++ drivers/scsi/qla2xxx/qla_init.c | 156 ++++++++++++++++++++++++++++++++++++++-- drivers/scsi/qla2xxx/qla_iocb.c | 64 +++++++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 102 ++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_mbx.c | 10 +++ drivers/scsi/qla2xxx/qla_os.c | 5 ++ 8 files changed, 366 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 951db816ee4..b905dfe5ea6 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -317,6 +317,9 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) els->type = (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); + els->name = + (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? + "bsg_els_rpt" : "bsg_els_hst"); els->u.bsg_job = bsg_job; DEBUG2(qla_printk(KERN_INFO, ha, @@ -450,6 +453,7 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) ct = sp->ctx; ct->type = SRB_CT_CMD; + ct->name = "bsg_ct"; ct->u.bsg_job = bsg_job; DEBUG2(qla_printk(KERN_INFO, ha, diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 08f5fd5359d..0d2cecbb8f4 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -223,6 +223,26 @@ struct srb_iocb { #define SRB_LOGIN_SKIP_PRLI BIT_2 uint16_t data[2]; } logio; + struct { + /* + * Values for flags field below are as + * defined in tsk_mgmt_entry struct + * for control_flags field in qla_fw.h. + */ + uint32_t flags; + uint32_t lun; + uint32_t data; + } tmf; + struct { + /* + * values for modif field below are as + * defined in mrk_entry_24xx struct + * for the modifier field in qla_fw.h. + */ + uint8_t modif; + uint16_t lun; + uint32_t data; + } marker; } u; struct timer_list timer; @@ -239,6 +259,8 @@ struct srb_iocb { #define SRB_ELS_CMD_HST 4 #define SRB_CT_CMD 5 #define SRB_ADISC_CMD 6 +#define SRB_TM_CMD 7 +#define SRB_MARKER_CMD 8 struct srb_ctx { uint16_t type; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 408e5f0a53c..3dbefe1a6b5 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -58,12 +58,18 @@ extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *, extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *, uint16_t *); +extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t); +extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t); extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); +extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *, + struct srb_iocb *); +extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *, + struct srb_iocb *); extern fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); @@ -87,6 +93,7 @@ extern int ql2xetsenable; extern int ql2xshiftctondsd; extern int ql2xdbwr; extern int ql2xdontresethba; +extern int ql2xasynctmfenable; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 72b4ef27015..e78089ded51 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -125,7 +125,7 @@ done: #define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2) static void -qla2x00_async_logio_timeout(srb_t *sp) +qla2x00_async_iocb_timeout(srb_t *sp) { fc_port_t *fcport = sp->fcport; struct srb_ctx *ctx = sp->ctx; @@ -170,7 +170,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, ctx->type = SRB_LOGIN_CMD; ctx->name = "login"; lio = ctx->u.iocb_cmd; - lio->timeout = qla2x00_async_logio_timeout; + lio->timeout = qla2x00_async_iocb_timeout; lio->done = qla2x00_async_login_ctx_done; lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) @@ -222,7 +222,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) ctx->type = SRB_LOGOUT_CMD; ctx->name = "logout"; lio = ctx->u.iocb_cmd; - lio->timeout = qla2x00_async_logio_timeout; + lio->timeout = qla2x00_async_iocb_timeout; lio->done = qla2x00_async_logout_ctx_done; rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) @@ -271,7 +271,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, ctx->type = SRB_ADISC_CMD; ctx->name = "adisc"; lio = ctx->u.iocb_cmd; - lio->timeout = qla2x00_async_logio_timeout; + lio->timeout = qla2x00_async_iocb_timeout; lio->done = qla2x00_async_adisc_ctx_done; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) lio->u.logio.flags |= SRB_LOGIN_RETRIED; @@ -292,6 +292,112 @@ done: return rval; } +static void +qla2x00_async_tm_cmd_ctx_done(srb_t *sp) +{ + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd; + + qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb); + iocb->free(sp); +} + +int +qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, + uint32_t tag) +{ + struct scsi_qla_host *vha = fcport->vha; + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_ctx *ctx; + struct srb_iocb *tcf; + int rval; + + rval = QLA_FUNCTION_FAILED; + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), + ELS_TMO_2_RATOV(ha) + 2); + if (!sp) + goto done; + + ctx = sp->ctx; + ctx->type = SRB_TM_CMD; + ctx->name = "tmf"; + tcf = ctx->u.iocb_cmd; + tcf->u.tmf.flags = flags; + tcf->u.tmf.lun = lun; + tcf->u.tmf.data = tag; + tcf->timeout = qla2x00_async_iocb_timeout; + tcf->done = qla2x00_async_tm_cmd_ctx_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n", + fcport->vha->host_no, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa)); + + return rval; + +done_free_sp: + tcf->free(sp); +done: + return rval; +} + +static void +qla2x00_async_marker_ctx_done(srb_t *sp) +{ + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd; + + qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb); + iocb->free(sp); +} + +int +qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif) +{ + struct scsi_qla_host *vha = fcport->vha; + srb_t *sp; + struct srb_ctx *ctx; + struct srb_iocb *mrk; + int rval; + + rval = QLA_FUNCTION_FAILED; + sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0); + if (!sp) + goto done; + + ctx = sp->ctx; + ctx->type = SRB_MARKER_CMD; + ctx->name = "marker"; + mrk = ctx->u.iocb_cmd; + mrk->u.marker.lun = lun; + mrk->u.marker.modif = modif; + mrk->timeout = qla2x00_async_iocb_timeout; + mrk->done = qla2x00_async_marker_ctx_done; + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-marker - loop-id=%x " + "portid=%02x%02x%02x.\n", + fcport->vha->host_no, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa)); + + return rval; + +done_free_sp: + mrk->free(sp); +done: + return rval; +} + void qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) @@ -360,6 +466,48 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, return; } +void +qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport, + struct srb_iocb *iocb) +{ + int rval; + uint32_t flags; + uint16_t lun; + + flags = iocb->u.tmf.flags; + lun = (uint16_t)iocb->u.tmf.lun; + + /* Issue Marker IOCB */ + rval = qla2x00_async_marker(fcport, lun, + flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); + + if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) { + DEBUG2_3_11(printk(KERN_WARNING + "%s(%ld): TM IOCB failed (%x).\n", + __func__, vha->host_no, rval)); + } + + return; +} + +void +qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport, + struct srb_iocb *iocb) +{ + /* + * Currently we dont have any specific post response processing + * for this IOCB. We'll just return success or failed + * depending on whether the IOCB command succeeded or failed. + */ + if (iocb->u.tmf.data) { + DEBUG2_3_11(printk(KERN_WARNING + "%s(%ld): Marker IOCB failed (%x).\n", + __func__, vha->host_no, iocb->u.tmf.data)); + } + + return; +} + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8861b88319f..d7a9fff15ad 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1085,6 +1085,64 @@ qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); } +static void +qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) +{ + uint32_t flags; + unsigned int lun; + struct fc_port *fcport = sp->fcport; + scsi_qla_host_t *vha = fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *iocb = ctx->u.iocb_cmd; + struct req_que *req = vha->req; + + flags = iocb->u.tmf.flags; + lun = iocb->u.tmf.lun; + + tsk->entry_type = TSK_MGMT_IOCB_TYPE; + tsk->entry_count = 1; + tsk->handle = MAKE_HANDLE(req->id, tsk->handle); + tsk->nport_handle = cpu_to_le16(fcport->loop_id); + tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); + tsk->control_flags = cpu_to_le32(flags); + tsk->port_id[0] = fcport->d_id.b.al_pa; + tsk->port_id[1] = fcport->d_id.b.area; + tsk->port_id[2] = fcport->d_id.b.domain; + tsk->vp_index = fcport->vp_idx; + + if (flags == TCF_LUN_RESET) { + int_to_scsilun(lun, &tsk->lun); + host_to_fcp_swap((uint8_t *)&tsk->lun, + sizeof(tsk->lun)); + } +} + +static void +qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk) +{ + uint16_t lun; + uint8_t modif; + struct fc_port *fcport = sp->fcport; + scsi_qla_host_t *vha = fcport->vha; + struct srb_ctx *ctx = sp->ctx; + struct srb_iocb *iocb = ctx->u.iocb_cmd; + struct req_que *req = vha->req; + + lun = iocb->u.marker.lun; + modif = iocb->u.marker.modif; + mrk->entry_type = MARKER_TYPE; + mrk->modifier = modif; + if (modif != MK_SYNC_ALL) { + mrk->nport_handle = cpu_to_le16(fcport->loop_id); + mrk->lun[1] = LSB(lun); + mrk->lun[2] = MSB(lun); + host_to_fcp_swap(mrk->lun, sizeof(mrk->lun)); + mrk->vp_index = vha->vp_idx; + mrk->handle = MAKE_HANDLE(req->id, mrk->handle); + } +} + static void qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { @@ -1239,6 +1297,12 @@ qla2x00_start_sp(srb_t *sp) qla24xx_adisc_iocb(sp, pkt) : qla2x00_adisc_iocb(sp, pkt); break; + case SRB_TM_CMD: + qla24xx_tm_iocb(sp, pkt); + break; + case SRB_MARKER_CMD: + qla24xx_marker_iocb(sp, pkt); + break; default: break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 166bb2045fd..eed71ea1d94 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1161,6 +1161,99 @@ logio_done: lio->done(sp); } +static void +qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + struct tsk_mgmt_entry *tsk) +{ + const char func[] = "TMF-IOCB"; + const char *type; + fc_port_t *fcport; + srb_t *sp; + struct srb_iocb *iocb; + struct srb_ctx *ctx; + struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; + int error = 1; + + sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); + if (!sp) + return; + + ctx = sp->ctx; + iocb = ctx->u.iocb_cmd; + type = ctx->name; + fcport = sp->fcport; + + if (sts->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error - entry-status(%x).\n", + fcport->vha->host_no, sp->handle, type, + sts->entry_status)); + } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error - completion status(%x).\n", + fcport->vha->host_no, sp->handle, type, + sts->comp_status)); + } else if (!(le16_to_cpu(sts->scsi_status) & + SS_RESPONSE_INFO_LEN_VALID)) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error - no response info(%x).\n", + fcport->vha->host_no, sp->handle, type, + sts->scsi_status)); + } else if (le32_to_cpu(sts->rsp_data_len) < 4) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error - not enough response(%d).\n", + fcport->vha->host_no, sp->handle, type, + sts->rsp_data_len)); + } else if (sts->data[3]) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error - response(%x).\n", + fcport->vha->host_no, sp->handle, type, + sts->data[3])); + } else { + error = 0; + } + + if (error) { + iocb->u.tmf.data = error; + DEBUG2(qla2x00_dump_buffer((uint8_t *)sts, sizeof(*sts))); + } + + iocb->done(sp); +} + +static void +qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + struct mrk_entry_24xx *mrk) +{ + const char func[] = "MRK-IOCB"; + const char *type; + fc_port_t *fcport; + srb_t *sp; + struct srb_iocb *iocb; + struct srb_ctx *ctx; + struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk; + + sp = qla2x00_get_sp_from_handle(vha, func, req, mrk); + if (!sp) + return; + + ctx = sp->ctx; + iocb = ctx->u.iocb_cmd; + type = ctx->name; + fcport = sp->fcport; + + if (sts->entry_status) { + iocb->u.marker.data = 1; + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", + fcport->vha->host_no, sp->handle, type, + sts->entry_status)); + DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts))); + } + + iocb->done(sp); +} + /** * qla2x00_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -1225,6 +1318,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp) case MBX_IOCB_TYPE: qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1751,6 +1845,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_logio_entry(vha, rsp->req, (struct logio_entry_24xx *)pkt); break; + case TSK_MGMT_IOCB_TYPE: + qla24xx_tm_iocb_entry(vha, rsp->req, + (struct tsk_mgmt_entry *)pkt); + break; + case MARKER_TYPE: + qla24xx_marker_iocb_entry(vha, rsp->req, + (struct mrk_entry_24xx *)pkt); + break; case CT_IOCB_TYPE: qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 2f303322806..f3650d0434c 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2464,12 +2464,22 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, int qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag) { + struct qla_hw_data *ha = fcport->vha->hw; + + if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha)) + return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag); + return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag); } int qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag) { + struct qla_hw_data *ha = fcport->vha->hw; + + if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha)) + return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag); + return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag); } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 70651f9fa65..523d414b59a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -142,6 +142,11 @@ MODULE_PARM_DESC(ql2xdontresethba, " 1 -- Do not reset on failure.\n"); +int ql2xasynctmfenable; +module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xasynctmfenable, + "Enables issue of TM IOCBs asynchronously via IOCB mechanism" + "Default is 0 - Issue TM IOCBs via mailbox mechanism."); /* * SCSI host template entry points */ -- cgit v1.2.3-70-g09d2 From bad750028917a7b804623701d0674e46c6012c18 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 4 May 2010 15:01:30 -0700 Subject: [SCSI] qla2xxx: T10 DIF support added. Signed-off-by: Duane Grigsby Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 16 + drivers/scsi/qla2xxx/qla_dbg.c | 58 ++++ drivers/scsi/qla2xxx/qla_dbg.h | 10 + drivers/scsi/qla2xxx/qla_def.h | 84 ++++- drivers/scsi/qla2xxx/qla_fw.h | 47 ++- drivers/scsi/qla2xxx/qla_gbl.h | 4 + drivers/scsi/qla2xxx/qla_inline.h | 16 + drivers/scsi/qla2xxx/qla_iocb.c | 678 +++++++++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_isr.c | 77 +++++ drivers/scsi/qla2xxx/qla_os.c | 75 ++++- 10 files changed, 1053 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/qla2xxx/qla_isr.c') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 5c98b097cfd..62a22cfae20 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1726,6 +1726,22 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); } + if (IS_QLA25XX(ha) && ql2xenabledif) { + if (ha->fw_attributes & BIT_4) { + vha->flags.difdix_supported = 1; + DEBUG18(qla_printk(KERN_INFO, ha, + "Registering for DIF/DIX type 1 and 3" + " protection.\n")); + scsi_host_set_prot(vha->host, + SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE3_PROTECTION + | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE3_PROTECTION); + scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC); + } else + vha->flags.difdix_supported = 0; + } + if (scsi_add_host_with_dma(vha->host, &fc_vport->dev, &ha->pdev->dev)) { DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n", diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 89bfc119010..2afc8a362f2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1663,4 +1663,62 @@ qla2x00_dump_buffer(uint8_t * b, uint32_t size) printk("\n"); } +void +qla2x00_dump_buffer_zipped(uint8_t *b, uint32_t size) +{ + uint32_t cnt; + uint8_t c; + uint8_t last16[16], cur16[16]; + uint32_t lc = 0, num_same16 = 0, j; + + printk(KERN_DEBUG " 0 1 2 3 4 5 6 7 8 9 " + "Ah Bh Ch Dh Eh Fh\n"); + printk(KERN_DEBUG "----------------------------------------" + "----------------------\n"); + + for (cnt = 0; cnt < size;) { + c = *b++; + cur16[lc++] = c; + + cnt++; + if (cnt % 16) + continue; + + /* We have 16 now */ + lc = 0; + if (num_same16 == 0) { + memcpy(last16, cur16, 16); + num_same16++; + continue; + } + if (memcmp(cur16, last16, 16) == 0) { + num_same16++; + continue; + } + for (j = 0; j < 16; j++) + printk(KERN_DEBUG "%02x ", (uint32_t)last16[j]); + printk(KERN_DEBUG "\n"); + + if (num_same16 > 1) + printk(KERN_DEBUG "> prev pattern repeats (%u)" + "more times\n", num_same16-1); + memcpy(last16, cur16, 16); + num_same16 = 1; + } + + if (num_same16) { + for (j = 0; j < 16; j++) + printk(KERN_DEBUG "%02x ", (uint32_t)last16[j]); + printk(KERN_DEBUG "\n"); + + if (num_same16 > 1) + printk(KERN_DEBUG "> prev pattern repeats (%u)" + "more times\n", num_same16-1); + } + if (lc) { + for (j = 0; j < lc; j++) + printk(KERN_DEBUG "%02x ", (uint32_t)cur16[j]); + printk(KERN_DEBUG "\n"); + } +} diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index d6d9c86cb05..916c81f3f55 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -27,6 +27,9 @@ /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */ /* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */ /* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */ +/* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */ + +/* #define QL_PRINTK_BUF */ /* Captures printk to buffer */ /* * Macros use for debugging the driver. @@ -139,6 +142,13 @@ #define DEBUG17(x) do {} while (0) #endif +#if defined(QL_DEBUG_LEVEL_18) +#define DEBUG18(x) do {if (ql2xextended_error_logging) x; } while (0) +#else +#define DEBUG18(x) do {} while (0) +#endif + + /* * Firmware Dump structure definition */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 0d2cecbb8f4..4559f5c6c1a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -188,6 +188,16 @@ struct req_que; +/* + * (sd.h is not exported, hence local inclusion) + * Data Integrity Field tuple. + */ +struct sd_dif_tuple { + __be16 guard_tag; /* Checksum */ + __be16 app_tag; /* Opaque storage */ + __be32 ref_tag; /* Target LBA or indirect LBA */ +}; + /* * SCSI Request Block */ @@ -208,8 +218,14 @@ typedef struct srb { /* * SRB flag definitions */ -#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ -#define SRB_FCP_CMND_DMA_VALID BIT_12 /* FCP command in IOCB */ +#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ +#define SRB_FCP_CMND_DMA_VALID BIT_12 /* DIF: DSD List valid */ +#define SRB_CRC_CTX_DMA_VALID BIT_2 /* DIF: context DMA valid */ +#define SRB_CRC_PROT_DMA_VALID BIT_4 /* DIF: prot DMA valid */ +#define SRB_CRC_CTX_DSD_VALID BIT_5 /* DIF: dsd_list valid */ + +/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */ +#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID) /* * SRB extensions. @@ -1330,6 +1346,66 @@ typedef struct { uint32_t dseg_4_length; /* Data segment 4 length. */ } cont_a64_entry_t; +#define PO_MODE_DIF_INSERT 0 +#define PO_MODE_DIF_REMOVE BIT_0 +#define PO_MODE_DIF_PASS BIT_1 +#define PO_MODE_DIF_REPLACE (BIT_0 + BIT_1) +#define PO_ENABLE_DIF_BUNDLING BIT_8 +#define PO_ENABLE_INCR_GUARD_SEED BIT_3 +#define PO_DISABLE_INCR_REF_TAG BIT_5 +#define PO_DISABLE_GUARD_CHECK BIT_4 +/* + * ISP queue - 64-Bit addressing, continuation crc entry structure definition. + */ +struct crc_context { + uint32_t handle; /* System handle. */ + uint32_t ref_tag; + uint16_t app_tag; + uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ + uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ + uint16_t guard_seed; /* Initial Guard Seed */ + uint16_t prot_opts; /* Requested Data Protection Mode */ + uint16_t blk_size; /* Data size in bytes */ + uint16_t runt_blk_guard; /* Guard value for runt block (tape + * only) */ + uint32_t byte_count; /* Total byte count/ total data + * transfer count */ + union { + struct { + uint32_t reserved_1; + uint16_t reserved_2; + uint16_t reserved_3; + uint32_t reserved_4; + uint32_t data_address[2]; + uint32_t data_length; + uint32_t reserved_5[2]; + uint32_t reserved_6; + } nobundling; + struct { + uint32_t dif_byte_count; /* Total DIF byte + * count */ + uint16_t reserved_1; + uint16_t dseg_count; /* Data segment count */ + uint32_t reserved_2; + uint32_t data_address[2]; + uint32_t data_length; + uint32_t dif_address[2]; + uint32_t dif_length; /* Data segment 0 + * length */ + } bundling; + } u; + + struct fcp_cmnd fcp_cmnd; + dma_addr_t crc_ctx_dma; + /* List of DMA context transfers */ + struct list_head dsd_list; + + /* This structure should not exceed 512 bytes */ +}; + +#define CRC_CONTEXT_LEN_FW (offsetof(struct crc_context, fcp_cmnd.lun)) +#define CRC_CONTEXT_FCPCMND_OFF (offsetof(struct crc_context, fcp_cmnd.lun)) + /* * ISP queue - status entry structure definition. */ @@ -1390,6 +1466,7 @@ typedef struct { #define CS_ABORTED 0x5 /* System aborted command. */ #define CS_TIMEOUT 0x6 /* Timeout error. */ #define CS_DATA_OVERRUN 0x7 /* Data overrun. */ +#define CS_DIF_ERROR 0xC /* DIF error detected */ #define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ #define CS_QUEUE_FULL 0x1C /* Queue Full. */ @@ -2732,6 +2809,7 @@ typedef struct scsi_qla_host { uint32_t management_server_logged_in :1; uint32_t process_response_queue :1; + uint32_t difdix_supported:1; } flags; atomic_t loop_state; @@ -2883,6 +2961,8 @@ typedef struct scsi_qla_host { #define OPTROM_BURST_SIZE 0x1000 #define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) +#define QLA_DSDS_PER_IOCB 37 + #include "qla_gbl.h" #include "qla_dbg.h" #include "qla_inline.h" diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index a77a2471eaf..93f83396014 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -400,6 +400,7 @@ struct cmd_type_6 { struct scsi_lun lun; /* FCP LUN (BE). */ uint16_t control_flags; /* Control flags. */ +#define CF_DIF_SEG_DESCR_ENABLE BIT_3 #define CF_DATA_SEG_DESCR_ENABLE BIT_2 #define CF_READ_DATA BIT_1 #define CF_WRITE_DATA BIT_0 @@ -466,6 +467,43 @@ struct cmd_type_7 { uint32_t dseg_0_len; /* Data segment 0 length. */ }; +#define COMMAND_TYPE_CRC_2 0x6A /* Command Type CRC_2 (Type 6) + * (T10-DIF) */ +struct cmd_type_crc_2 { + uint8_t entry_type; /* Entry type. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + + uint32_t handle; /* System handle. */ + + uint16_t nport_handle; /* N_PORT handle. */ + uint16_t timeout; /* Command timeout. */ + + uint16_t dseg_count; /* Data segment count. */ + + uint16_t fcp_rsp_dseg_len; /* FCP_RSP DSD length. */ + + struct scsi_lun lun; /* FCP LUN (BE). */ + + uint16_t control_flags; /* Control flags. */ + + uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ + uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */ + + uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */ + + uint32_t byte_count; /* Total byte count. */ + + uint8_t port_id[3]; /* PortID of destination port. */ + uint8_t vp_index; + + uint32_t crc_context_address[2]; /* Data segment address. */ + uint16_t crc_context_len; /* Data segment length. */ + uint16_t reserved_1; /* MUST be set to 0. */ +}; + + /* * ISP queue - status entry structure definition. */ @@ -496,10 +534,17 @@ struct sts_entry_24xx { uint32_t sense_len; /* FCP SENSE length. */ uint32_t rsp_data_len; /* FCP response data length. */ - uint8_t data[28]; /* FCP response/sense information. */ + /* + * If DIF Error is set in comp_status, these additional fields are + * defined: + * &data[10] : uint8_t report_runt_bg[2]; - computed guard + * &data[12] : uint8_t actual_dif[8]; - DIF Data recieved + * &data[20] : uint8_t expected_dif[8]; - DIF Data computed + */ }; + /* * Status entry completion status */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3dbefe1a6b5..3e946da74b9 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -94,6 +94,8 @@ extern int ql2xshiftctondsd; extern int ql2xdbwr; extern int ql2xdontresethba; extern int ql2xasynctmfenable; +extern int ql2xenabledif; +extern int ql2xenablehba_err_chk; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -179,6 +181,7 @@ extern int qla2x00_start_sp(srb_t *); extern void qla2x00_ctx_sp_free(srb_t *); extern uint16_t qla24xx_calc_iocbs(uint16_t); extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t); +extern int qla24xx_dif_start_scsi(srb_t *); /* @@ -423,6 +426,7 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int); extern void qla81xx_fw_dump(scsi_qla_host_t *, int); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); +extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t); /* * Global Function Prototypes in qla_gs.c source file. diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index ad53c645555..84c2fea154d 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -67,3 +67,19 @@ qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id) return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) || loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST); } + +static inline void +qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp) +{ + struct dsd_dma *dsd_ptr, *tdsd_ptr; + + /* clean up allocated prev pool */ + list_for_each_entry_safe(dsd_ptr, tdsd_ptr, + &((struct crc_context *)sp->ctx)->dsd_list, list) { + dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, + dsd_ptr->dsd_list_dma); + list_del(&dsd_ptr->list); + kfree(dsd_ptr); + } + INIT_LIST_HEAD(&((struct crc_context *)sp->ctx)->dsd_list); +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d7a9fff15ad..8ef94536541 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -145,7 +145,49 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha) return (cont_pkt); } -/** +static inline int +qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts) +{ + uint8_t guard = scsi_host_get_guard(sp->cmd->device->host); + + /* We only support T10 DIF right now */ + if (guard != SHOST_DIX_GUARD_CRC) { + DEBUG2(printk(KERN_ERR "Unsupported guard: %d\n", guard)); + return 0; + } + + /* We always use DIFF Bundling for best performance */ + *fw_prot_opts = 0; + + /* Translate SCSI opcode to a protection opcode */ + switch (scsi_get_prot_op(sp->cmd)) { + case SCSI_PROT_READ_STRIP: + *fw_prot_opts |= PO_MODE_DIF_REMOVE; + break; + case SCSI_PROT_WRITE_INSERT: + *fw_prot_opts |= PO_MODE_DIF_INSERT; + break; + case SCSI_PROT_READ_INSERT: + *fw_prot_opts |= PO_MODE_DIF_INSERT; + break; + case SCSI_PROT_WRITE_STRIP: + *fw_prot_opts |= PO_MODE_DIF_REMOVE; + break; + case SCSI_PROT_READ_PASS: + *fw_prot_opts |= PO_MODE_DIF_PASS; + break; + case SCSI_PROT_WRITE_PASS: + *fw_prot_opts |= PO_MODE_DIF_PASS; + break; + default: /* Normal Request */ + *fw_prot_opts |= PO_MODE_DIF_PASS; + break; + } + + return scsi_prot_sg_count(sp->cmd); +} + +/* * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit * capable IOCB types. * @@ -636,6 +678,8 @@ qla24xx_calc_iocbs(uint16_t dsds) if ((dsds - 1) % 5) iocbs++; } + DEBUG3(printk(KERN_DEBUG "%s(): Required PKT(s) = %d\n", + __func__, iocbs)); return iocbs; } @@ -716,6 +760,453 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, } } +struct fw_dif_context { + uint32_t ref_tag; + uint16_t app_tag; + uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ + uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ +}; + +/* + * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command + * + */ +static inline void +qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, + unsigned int protcnt) +{ + struct sd_dif_tuple *spt; + unsigned char op = scsi_get_prot_op(cmd); + + switch (scsi_get_prot_type(cmd)) { + /* For TYPE 0 protection: no checking */ + case SCSI_PROT_DIF_TYPE0: + pkt->ref_tag_mask[0] = 0x00; + pkt->ref_tag_mask[1] = 0x00; + pkt->ref_tag_mask[2] = 0x00; + pkt->ref_tag_mask[3] = 0x00; + break; + + /* + * For TYPE 2 protection: 16 bit GUARD + 32 bit REF tag has to + * match LBA in CDB + N + */ + case SCSI_PROT_DIF_TYPE2: + break; + + /* For Type 3 protection: 16 bit GUARD only */ + case SCSI_PROT_DIF_TYPE3: + pkt->ref_tag_mask[0] = pkt->ref_tag_mask[1] = + pkt->ref_tag_mask[2] = pkt->ref_tag_mask[3] = + 0x00; + break; + + /* + * For TYpe 1 protection: 16 bit GUARD tag, 32 bit REF tag, and + * 16 bit app tag. + */ + case SCSI_PROT_DIF_TYPE1: + if (!ql2xenablehba_err_chk) + break; + + if (protcnt && (op == SCSI_PROT_WRITE_STRIP || + op == SCSI_PROT_WRITE_PASS)) { + spt = page_address(sg_page(scsi_prot_sglist(cmd))) + + scsi_prot_sglist(cmd)[0].offset; + DEBUG18(printk(KERN_DEBUG + "%s(): LBA from user %p, lba = 0x%x\n", + __func__, spt, (int)spt->ref_tag)); + pkt->ref_tag = swab32(spt->ref_tag); + pkt->app_tag_mask[0] = 0x0; + pkt->app_tag_mask[1] = 0x0; + } else { + pkt->ref_tag = cpu_to_le32((uint32_t) + (0xffffffff & scsi_get_lba(cmd))); + pkt->app_tag = __constant_cpu_to_le16(0); + pkt->app_tag_mask[0] = 0x0; + pkt->app_tag_mask[1] = 0x0; + } + /* enable ALL bytes of the ref tag */ + pkt->ref_tag_mask[0] = 0xff; + pkt->ref_tag_mask[1] = 0xff; + pkt->ref_tag_mask[2] = 0xff; + pkt->ref_tag_mask[3] = 0xff; + break; + } + + DEBUG18(printk(KERN_DEBUG + "%s(): Setting protection Tags: (BIG) ref tag = 0x%x," + " app tag = 0x%x, prot SG count %d , cmd lba 0x%x," + " prot_type=%u\n", __func__, pkt->ref_tag, pkt->app_tag, protcnt, + (int)scsi_get_lba(cmd), scsi_get_prot_type(cmd))); +} + + +static int +qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, + uint16_t tot_dsds) +{ + void *next_dsd; + uint8_t avail_dsds = 0; + uint32_t dsd_list_len; + struct dsd_dma *dsd_ptr; + struct scatterlist *sg; + uint32_t *cur_dsd = dsd; + int i; + uint16_t used_dsds = tot_dsds; + + uint8_t *cp; + + scsi_for_each_sg(sp->cmd, sg, tot_dsds, i) { + dma_addr_t sle_dma; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + if (!dsd_ptr) + return 1; + + /* allocate new list */ + dsd_ptr->dsd_addr = next_dsd = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + + if (!next_dsd) { + /* + * Need to cleanup only this dsd_ptr, rest + * will be done by sp_free_dma() + */ + kfree(dsd_ptr); + return 1; + } + + list_add_tail(&dsd_ptr->list, + &((struct crc_context *)sp->ctx)->dsd_list); + + sp->flags |= SRB_CRC_CTX_DSD_VALID; + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = (uint32_t *)next_dsd; + } + sle_dma = sg_dma_address(sg); + DEBUG18(printk("%s(): %p, sg entry %d - addr =0x%x 0x%x," + " len =%d\n", __func__ , cur_dsd, i, LSD(sle_dma), + MSD(sle_dma), sg_dma_len(sg))); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + avail_dsds--; + + if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) { + cp = page_address(sg_page(sg)) + sg->offset; + DEBUG18(printk("%s(): User Data buffer= %p:\n", + __func__ , cp)); + } + } + /* Null termination */ + *cur_dsd++ = 0; + *cur_dsd++ = 0; + *cur_dsd++ = 0; + return 0; +} + +static int +qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, + uint32_t *dsd, + uint16_t tot_dsds) +{ + void *next_dsd; + uint8_t avail_dsds = 0; + uint32_t dsd_list_len; + struct dsd_dma *dsd_ptr; + struct scatterlist *sg; + int i; + struct scsi_cmnd *cmd; + uint32_t *cur_dsd = dsd; + uint16_t used_dsds = tot_dsds; + + uint8_t *cp; + + + cmd = sp->cmd; + scsi_for_each_prot_sg(cmd, sg, tot_dsds, i) { + dma_addr_t sle_dma; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + if (!dsd_ptr) + return 1; + + /* allocate new list */ + dsd_ptr->dsd_addr = next_dsd = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + + if (!next_dsd) { + /* + * Need to cleanup only this dsd_ptr, rest + * will be done by sp_free_dma() + */ + kfree(dsd_ptr); + return 1; + } + + list_add_tail(&dsd_ptr->list, + &((struct crc_context *)sp->ctx)->dsd_list); + + sp->flags |= SRB_CRC_CTX_DSD_VALID; + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = (uint32_t *)next_dsd; + } + sle_dma = sg_dma_address(sg); + if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) { + DEBUG18(printk(KERN_DEBUG + "%s(): %p, sg entry %d - addr =0x%x" + "0x%x, len =%d\n", __func__ , cur_dsd, i, + LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg))); + } + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + + if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) { + cp = page_address(sg_page(sg)) + sg->offset; + DEBUG18(printk("%s(): Protection Data buffer = %p:\n", + __func__ , cp)); + } + avail_dsds--; + } + /* Null termination */ + *cur_dsd++ = 0; + *cur_dsd++ = 0; + *cur_dsd++ = 0; + return 0; +} + +/** + * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command + * Type 6 IOCB types. + * + * @sp: SRB command to process + * @cmd_pkt: Command type 3 IOCB + * @tot_dsds: Total number of segments to transfer + */ +static inline int +qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, + uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) +{ + uint32_t *cur_dsd, *fcp_dl; + scsi_qla_host_t *vha; + struct scsi_cmnd *cmd; + struct scatterlist *cur_seg; + int sgc; + uint32_t total_bytes; + uint32_t data_bytes; + uint32_t dif_bytes; + uint8_t bundling = 1; + uint16_t blk_size; + uint8_t *clr_ptr; + struct crc_context *crc_ctx_pkt = NULL; + struct qla_hw_data *ha; + uint8_t additional_fcpcdb_len; + uint16_t fcp_cmnd_len; + struct fcp_cmnd *fcp_cmnd; + dma_addr_t crc_ctx_dma; + + cmd = sp->cmd; + + sgc = 0; + /* Update entry type to indicate Command Type CRC_2 IOCB */ + *((uint32_t *)(&cmd_pkt->entry_type)) = + __constant_cpu_to_le32(COMMAND_TYPE_CRC_2); + + /* No data transfer */ + data_bytes = scsi_bufflen(cmd); + if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { + DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n", + __func__, data_bytes)); + cmd_pkt->byte_count = __constant_cpu_to_le32(0); + return QLA_SUCCESS; + } + + vha = sp->fcport->vha; + ha = vha->hw; + + DEBUG18(printk(KERN_DEBUG + "%s(%ld): Executing cmd sp %p, pid=%ld, prot_op=%u.\n", __func__, + vha->host_no, sp, cmd->serial_number, scsi_get_prot_op(sp->cmd))); + + cmd_pkt->vp_index = sp->fcport->vp_idx; + + /* Set transfer direction */ + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_WRITE_DATA); + } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { + cmd_pkt->control_flags = + __constant_cpu_to_le16(CF_READ_DATA); + } + + tot_prot_dsds = scsi_prot_sg_count(cmd); + if (!tot_prot_dsds) + bundling = 0; + + /* Allocate CRC context from global pool */ + crc_ctx_pkt = sp->ctx = dma_pool_alloc(ha->dl_dma_pool, + GFP_ATOMIC, &crc_ctx_dma); + + if (!crc_ctx_pkt) + goto crc_queuing_error; + + /* Zero out CTX area. */ + clr_ptr = (uint8_t *)crc_ctx_pkt; + memset(clr_ptr, 0, sizeof(*crc_ctx_pkt)); + + crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; + + sp->flags |= SRB_CRC_CTX_DMA_VALID; + + /* Set handle */ + crc_ctx_pkt->handle = cmd_pkt->handle; + + INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); + + qla24xx_set_t10dif_tags(cmd, (struct fw_dif_context *) + &crc_ctx_pkt->ref_tag, tot_prot_dsds); + + cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma)); + cmd_pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma)); + cmd_pkt->crc_context_len = CRC_CONTEXT_LEN_FW; + + /* Determine SCSI command length -- align to 4 byte boundary */ + if (cmd->cmd_len > 16) { + DEBUG18(printk(KERN_INFO "%s(): **** SCSI CMD > 16\n", + __func__)); + additional_fcpcdb_len = cmd->cmd_len - 16; + if ((cmd->cmd_len % 4) != 0) { + /* SCSI cmd > 16 bytes must be multiple of 4 */ + goto crc_queuing_error; + } + fcp_cmnd_len = 12 + cmd->cmd_len + 4; + } else { + additional_fcpcdb_len = 0; + fcp_cmnd_len = 12 + 16 + 4; + } + + fcp_cmnd = &crc_ctx_pkt->fcp_cmnd; + + fcp_cmnd->additional_cdb_len = additional_fcpcdb_len; + if (cmd->sc_data_direction == DMA_TO_DEVICE) + fcp_cmnd->additional_cdb_len |= 1; + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + fcp_cmnd->additional_cdb_len |= 2; + + int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun); + memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); + cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); + cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32( + LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); + cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32( + MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); + fcp_cmnd->task_attribute = 0; + fcp_cmnd->task_managment = 0; + + cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ + + DEBUG18(printk(KERN_INFO "%s(%ld): Total SG(s) Entries %d, Data" + "entries %d, data bytes %d, Protection entries %d\n", + __func__, vha->host_no, tot_dsds, (tot_dsds-tot_prot_dsds), + data_bytes, tot_prot_dsds)); + + /* Compute dif len and adjust data len to incude protection */ + total_bytes = data_bytes; + dif_bytes = 0; + blk_size = cmd->device->sector_size; + if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE1) { + dif_bytes = (data_bytes / blk_size) * 8; + total_bytes += dif_bytes; + } + + if (!ql2xenablehba_err_chk) + fw_prot_opts |= 0x10; /* Disable Guard tag checking */ + + if (!bundling) { + cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address; + } else { + /* + * Configure Bundling if we need to fetch interlaving + * protection PCI accesses + */ + fw_prot_opts |= PO_ENABLE_DIF_BUNDLING; + crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); + crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - + tot_prot_dsds); + cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address; + } + + /* Finish the common fields of CRC pkt */ + crc_ctx_pkt->blk_size = cpu_to_le16(blk_size); + crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); + crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); + crc_ctx_pkt->guard_seed = __constant_cpu_to_le16(0); + /* Fibre channel byte count */ + cmd_pkt->byte_count = cpu_to_le32(total_bytes); + fcp_dl = (uint32_t *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 + + additional_fcpcdb_len); + *fcp_dl = htonl(total_bytes); + + DEBUG18(printk(KERN_INFO "%s(%ld): dif bytes = 0x%x (%d), total bytes" + " = 0x%x (%d), dat block size =0x%x (%d)\n", __func__, + vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes, + crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size)); + + /* Walks data segments */ + + cmd_pkt->control_flags |= + __constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); + if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, + (tot_dsds - tot_prot_dsds))) + goto crc_queuing_error; + + if (bundling && tot_prot_dsds) { + /* Walks dif segments */ + cur_seg = scsi_prot_sglist(cmd); + cmd_pkt->control_flags |= + __constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); + cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; + if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, + tot_prot_dsds)) + goto crc_queuing_error; + } + return QLA_SUCCESS; + +crc_queuing_error: + DEBUG18(qla_printk(KERN_INFO, ha, + "CMD sent FAILED crc_q error:sp = %p\n", sp)); + /* Cleanup will be performed by the caller */ + + return QLA_FUNCTION_FAILED; +} /** * qla24xx_start_scsi() - Send a SCSI command to the ISP @@ -869,6 +1360,191 @@ queuing_error: return QLA_FUNCTION_FAILED; } + +/** + * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occurred, else zero. + */ +int +qla24xx_dif_start_scsi(srb_t *sp) +{ + int nseg; + unsigned long flags; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + uint16_t cnt; + uint16_t req_cnt = 0; + uint16_t tot_dsds; + uint16_t tot_prot_dsds; + uint16_t fw_prot_opts = 0; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; + struct scsi_cmnd *cmd = sp->cmd; + struct scsi_qla_host *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct cmd_type_crc_2 *cmd_pkt; + uint32_t status = 0; + +#define QDSS_GOT_Q_SPACE BIT_0 + + /* Only process protection in this routine */ + if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) + return qla24xx_start_scsi(sp); + + /* Setup device pointers. */ + + qla25xx_set_que(sp, &rsp); + req = vha->req; + + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; + + /* Send marker if required */ + if (vha->marker_needed != 0) { + if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) + return QLA_FUNCTION_FAILED; + vha->marker_needed = 0; + } + + /* Acquire ring specific lock */ + spin_lock_irqsave(&ha->hardware_lock, flags); + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { + handle++; + if (handle == MAX_OUTSTANDING_COMMANDS) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + + if (index == MAX_OUTSTANDING_COMMANDS) + goto queuing_error; + + /* Compute number of required data segments */ + /* Map the sg table so we have an accurate count of sg entries needed */ + if (scsi_sg_count(cmd)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), + scsi_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + else + sp->flags |= SRB_DMA_VALID; + } else + nseg = 0; + + /* number of required data segments */ + tot_dsds = nseg; + + /* Compute number of required protection segments */ + if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), + scsi_prot_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + else + sp->flags |= SRB_CRC_PROT_DMA_VALID; + } else { + nseg = 0; + } + + req_cnt = 1; + /* Total Data and protection sg segment(s) */ + tot_prot_dsds = nseg; + tot_dsds += nseg; + if (req->cnt < (req_cnt + 2)) { + cnt = RD_REG_DWORD_RELAXED(req->req_q_out); + + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + + status |= QDSS_GOT_Q_SPACE; + + /* Build header part of command packet (excluding the OPCODE). */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; + req->cnt -= req_cnt; + + /* Fill-in common area */ + cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + + /* Set NPORT-ID and LUN number*/ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + + int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + + /* Total Data and protection segment(s) */ + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Build IOCB segments and adjust for data protection segments */ + if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) + req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != + QLA_SUCCESS) + goto queuing_error; + + cmd_pkt->entry_count = (uint8_t)req_cnt; + /* Specify response queue number where completion should happen */ + cmd_pkt->entry_status = (uint8_t) rsp->id; + cmd_pkt->timeout = __constant_cpu_to_le16(0); + wmb(); + + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + /* Set chip new ring index. */ + WRT_REG_DWORD(req->req_q_in, req->ring_index); + RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); + + /* Manage unprocessed RIO/ZIO commands in response queue. */ + if (vha->flags.process_response_queue && + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(vha, rsp); + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return QLA_SUCCESS; + +queuing_error: + if (status & QDSS_GOT_Q_SPACE) { + req->outstanding_cmds[handle] = NULL; + req->cnt += req_cnt; + } + /* Cleanup will be performed by the caller (queuecommand) */ + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + DEBUG18(qla_printk(KERN_INFO, ha, + "CMD sent FAILED SCSI prot_op:%02x\n", scsi_get_prot_op(cmd))); + return QLA_FUNCTION_FAILED; +} + + static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) { struct scsi_cmnd *cmd = sp->cmd; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index eed71ea1d94..be3d8bed2ec 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -10,6 +10,7 @@ #include #include #include +#include static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_process_completed_request(struct scsi_qla_host *, @@ -1364,6 +1365,78 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len, DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len)); } +struct scsi_dif_tuple { + __be16 guard; /* Checksum */ + __be16 app_tag; /* APPL identifer */ + __be32 ref_tag; /* Target LBA or indirect LBA */ +}; + +/* + * Checks the guard or meta-data for the type of error + * detected by the HBA. In case of errors, we set the + * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST + * to indicate to the kernel that the HBA detected error. + */ +static inline void +qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) +{ + struct scsi_cmnd *cmd = sp->cmd; + struct scsi_dif_tuple *ep = + (struct scsi_dif_tuple *)&sts24->data[20]; + struct scsi_dif_tuple *ap = + (struct scsi_dif_tuple *)&sts24->data[12]; + uint32_t e_ref_tag, a_ref_tag; + uint16_t e_app_tag, a_app_tag; + uint16_t e_guard, a_guard; + + e_ref_tag = be32_to_cpu(ep->ref_tag); + a_ref_tag = be32_to_cpu(ap->ref_tag); + e_app_tag = be16_to_cpu(ep->app_tag); + a_app_tag = be16_to_cpu(ap->app_tag); + e_guard = be16_to_cpu(ep->guard); + a_guard = be16_to_cpu(ap->guard); + + DEBUG18(printk(KERN_DEBUG + "%s(): iocb(s) %p Returned STATUS\n", __func__, sts24)); + + DEBUG18(printk(KERN_ERR "DIF ERROR in cmd 0x%x lba 0x%llx act ref" + " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app" + " tag=0x%x, act guard=0x%x, exp guard=0x%x\n", + cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, + a_app_tag, e_app_tag, a_guard, e_guard)); + + + /* check guard */ + if (e_guard != a_guard) { + scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, + 0x10, 0x1); + set_driver_byte(cmd, DRIVER_SENSE); + set_host_byte(cmd, DID_ABORT); + cmd->result |= SAM_STAT_CHECK_CONDITION << 1; + return; + } + + /* check appl tag */ + if (e_app_tag != a_app_tag) { + scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, + 0x10, 0x2); + set_driver_byte(cmd, DRIVER_SENSE); + set_host_byte(cmd, DID_ABORT); + cmd->result |= SAM_STAT_CHECK_CONDITION << 1; + return; + } + + /* check ref tag */ + if (e_ref_tag != a_ref_tag) { + scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, + 0x10, 0x3); + set_driver_byte(cmd, DRIVER_SENSE); + set_host_byte(cmd, DID_ABORT); + cmd->result |= SAM_STAT_CHECK_CONDITION << 1; + return; + } +} + /** * qla2x00_status_entry() - Process a Status IOCB entry. * @ha: SCSI driver HA context @@ -1630,6 +1703,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) case CS_ABORTED: cp->result = DID_RESET << 16; break; + + case CS_DIF_ERROR: + qla2x00_handle_dif_error(sp, sts24); + break; default: cp->result = DID_ERROR << 16; break; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 523d414b59a..5104aefdc7e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -92,6 +92,19 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xmaxqdepth, "Maximum queue depth to report for target devices."); +/* Do not change the value of this after module load */ +int ql2xenabledif = 1; +module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xenabledif, + " Enable T10-CRC-DIF " + " Default is 0 - No DIF Support. 1 - Enable it"); + +int ql2xenablehba_err_chk; +module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql2xenablehba_err_chk, + " Enable T10-CRC-DIF Error isolation by HBA" + " Default is 0 - Error isolation disabled, 1 - Enable it"); + int ql2xiidmaenable=1; module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xiidmaenable, @@ -537,6 +550,14 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) if (fcport->drport) goto qc24_target_busy; + if (!vha->flags.difdix_supported && + scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { + DEBUG2(qla_printk(KERN_ERR, ha, + "DIF Cap Not Reg, fail DIF capable cmd's:%x\n", + cmd->cmnd[0])); + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } if (atomic_read(&fcport->state) != FCS_ONLINE) { if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || atomic_read(&base_vha->loop_state) == LOOP_DEAD) { @@ -776,7 +797,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (sp == NULL) continue; - if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID)) + if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID) && + !IS_PROT_IO(sp)) continue; if (sp->cmd != cmd) continue; @@ -842,7 +864,7 @@ 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) + if ((sp->ctx) && !IS_PROT_IO(sp)) continue; if (vha->vp_idx != sp->fcport->vha->vp_idx) continue; @@ -1189,7 +1211,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) if (sp) { req->outstanding_cmds[cnt] = NULL; if (!sp->ctx || - (sp->flags & SRB_FCP_CMND_DMA_VALID)) { + (sp->flags & SRB_FCP_CMND_DMA_VALID) || + IS_PROT_IO(sp)) { sp->cmd->result = res; qla2x00_sp_compl(ha, sp); } else { @@ -1553,7 +1576,7 @@ static struct isp_operations qla25xx_isp_ops = { .read_optrom = qla25xx_read_optrom_data, .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla24xx_start_scsi, + .start_scsi = qla24xx_dif_start_scsi, .abort_isp = qla2x00_abort_isp, }; @@ -2185,6 +2208,22 @@ skip_dpc: DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", base_vha->host_no, ha)); + if (IS_QLA25XX(ha) && ql2xenabledif) { + if (ha->fw_attributes & BIT_4) { + base_vha->flags.difdix_supported = 1; + DEBUG18(qla_printk(KERN_INFO, ha, + "Registering for DIF/DIX type 1 and 3" + " protection.\n")); + scsi_host_set_prot(host, + SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE3_PROTECTION + | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE3_PROTECTION); + scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC); + } else + base_vha->flags.difdix_supported = 0; + } + ha->isp_ops->enable_intrs(ha); ret = scsi_add_host(host, &pdev->dev); @@ -2546,7 +2585,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, if (!ha->s_dma_pool) goto fail_free_nvram; - if (IS_QLA82XX(ha)) { + if (IS_QLA82XX(ha) || ql2xenabledif) { ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev, DSD_LIST_DMA_POOL_SIZE, 8, 0); if (!ha->dl_dma_pool) { @@ -2678,12 +2717,12 @@ fail_free_ms_iocb: ha->ms_iocb = NULL; ha->ms_iocb_dma = 0; fail_dma_pool: - if (IS_QLA82XX(ha)) { + if (IS_QLA82XX(ha) || ql2xenabledif) { dma_pool_destroy(ha->fcp_cmnd_dma_pool); ha->fcp_cmnd_dma_pool = NULL; } fail_dl_dma_pool: - if (IS_QLA82XX(ha)) { + if (IS_QLA82XX(ha) || ql2xenabledif) { dma_pool_destroy(ha->dl_dma_pool); ha->dl_dma_pool = NULL; } @@ -3346,11 +3385,31 @@ static void qla2x00_sp_free_dma(srb_t *sp) { struct scsi_cmnd *cmd = sp->cmd; + struct qla_hw_data *ha = sp->fcport->vha->hw; if (sp->flags & SRB_DMA_VALID) { scsi_dma_unmap(cmd); sp->flags &= ~SRB_DMA_VALID; } + + if (sp->flags & SRB_CRC_PROT_DMA_VALID) { + dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), + scsi_prot_sg_count(cmd), cmd->sc_data_direction); + sp->flags &= ~SRB_CRC_PROT_DMA_VALID; + } + + if (sp->flags & SRB_CRC_CTX_DSD_VALID) { + /* List assured to be having elements */ + qla2x00_clean_dsd_pool(ha, sp); + sp->flags &= ~SRB_CRC_CTX_DSD_VALID; + } + + if (sp->flags & SRB_CRC_CTX_DMA_VALID) { + dma_pool_free(ha->dl_dma_pool, sp->ctx, + ((struct crc_context *)sp->ctx)->crc_ctx_dma); + sp->flags &= ~SRB_CRC_CTX_DMA_VALID; + } + CMD_SP(cmd) = NULL; } @@ -3464,7 +3523,7 @@ qla2x00_timer(scsi_qla_host_t *vha) sp = req->outstanding_cmds[index]; if (!sp) continue; - if (sp->ctx) + if (sp->ctx && !IS_PROT_IO(sp)) continue; sfcp = sp->fcport; if (!(sfcp->flags & FCF_FCP2_DEVICE)) -- cgit v1.2.3-70-g09d2