diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_isr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 309 |
1 files changed, 304 insertions, 5 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 245e7afb4c4..b20a7169aac 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -598,9 +598,54 @@ skip_rio: break; case MBA_PORT_UPDATE: /* Port database update */ - /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + /* + * Handle only global and vn-port update events + * + * Relevant inputs: + * mb[1] = N_Port handle of changed port + * OR 0xffff for global event + * mb[2] = New login state + * 7 = Port logged out + * mb[3] = LSB is vp_idx, 0xff = all vps + * + * Skip processing if: + * Event is global, vp_idx is NOT all vps, + * vp_idx does not match + * Event is not global, vp_idx does not match + */ + if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) + || (mb[1] != 0xffff)) { + if (vha->vp_idx != (mb[3] & 0xff)) + break; + } + + /* Global event -- port logout or port unavailable. */ + if (mb[1] == 0xffff && mb[2] == 0x7) { + DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n", + vha->host_no)); + DEBUG(printk(KERN_INFO + "scsi(%ld): Port unavailable %04x %04x %04x.\n", + vha->host_no, mb[1], mb[2], mb[3])); + + if (atomic_read(&vha->loop_state) != LOOP_DOWN) { + atomic_set(&vha->loop_state, LOOP_DOWN); + atomic_set(&vha->loop_down_timer, + LOOP_DOWN_TIME); + vha->device_flags |= DFLG_NO_CABLE; + qla2x00_mark_all_devices_lost(vha, 1); + } + + if (vha->vp_idx) { + atomic_set(&vha->vp_state, VP_FAILED); + fc_vport_set_state(vha->fc_vport, + FC_VPORT_FAILED); + qla2x00_mark_all_devices_lost(vha, 1); + } + + vha->flags.management_server_logged_in = 0; + ha->link_data_rate = PORT_SPEED_UNKNOWN; break; + } /* * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET @@ -640,8 +685,9 @@ skip_rio: if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags)) break; /* Only handle SCNs for our Vport index. */ - if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff)) + if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff)) break; + DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", vha->host_no)); DEBUG(printk(KERN_INFO @@ -874,6 +920,249 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, } } +static srb_t * +qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, + struct req_que *req, void *iocb) +{ + struct qla_hw_data *ha = vha->hw; + sts_entry_t *pkt = iocb; + srb_t *sp = NULL; + uint16_t index; + + index = LSW(pkt->handle); + if (index >= MAX_OUTSTANDING_COMMANDS) { + qla_printk(KERN_WARNING, ha, + "%s: Invalid completion handle (%x).\n", func, index); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + goto done; + } + sp = req->outstanding_cmds[index]; + if (!sp) { + qla_printk(KERN_WARNING, ha, + "%s: Invalid completion handle (%x) -- timed-out.\n", func, + index); + return sp; + } + if (sp->handle != index) { + qla_printk(KERN_WARNING, ha, + "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle, + index); + return NULL; + } + req->outstanding_cmds[index] = NULL; +done: + return sp; +} + +static void +qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + struct mbx_entry *mbx) +{ + 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]; + + 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); + fcport = sp->fcport; + + data[0] = data[1] = 0; + if (mbx->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x " + "status=%x state-flag=%x status-flags=%x.\n", + fcport->vha->host_no, sp->handle, type, + mbx->entry_status, le16_to_cpu(mbx->status), + le16_to_cpu(mbx->state_flags), + 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 done_post_logio_done_work; + } + + if (!mbx->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 && le16_to_cpu(mbx->mb1) & BIT_1) + fcport->flags |= FCF_FCP2_DEVICE; + + goto done_post_logio_done_work; + } + + data[0] = le16_to_cpu(mbx->mb0); + switch (data[0]) { + case MBS_PORT_ID_USED: + data[1] = le16_to_cpu(mbx->mb1); + break; + case MBS_LOOP_ID_USED: + 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), + 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))); + +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); +} + +static void +qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, + struct logio_entry_24xx *logio) +{ + 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]; + 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); + fcport = sp->fcport; + + data[0] = data[1] = 0; + if (logio->entry_status) { + DEBUG2(printk(KERN_WARNING + "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", + fcport->vha->host_no, sp->handle, type, + 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 done_post_logio_done_work; + } + + if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { + DEBUG2(printk(KERN_DEBUG + "scsi(%ld:%x): Async-%s complete - iop0=%x.\n", + fcport->vha->host_no, sp->handle, type, + le32_to_cpu(logio->io_parameter[0]))); + + data[0] = MBS_COMMAND_COMPLETE; + if (lio->ctx.type == SRB_LOGOUT_CMD) + goto done_post_logio_done_work; + + iop[0] = le32_to_cpu(logio->io_parameter[0]); + if (iop[0] & BIT_4) { + fcport->port_type = FCT_TARGET; + if (iop[0] & BIT_8) + fcport->flags |= FCF_FCP2_DEVICE; + } + if (iop[0] & BIT_5) + fcport->port_type = FCT_INITIATOR; + if (logio->io_parameter[7] || logio->io_parameter[8]) + fcport->supported_classes |= FC_COS_CLASS2; + if (logio->io_parameter[9] || logio->io_parameter[10]) + fcport->supported_classes |= FC_COS_CLASS3; + + goto done_post_logio_done_work; + } + + iop[0] = le32_to_cpu(logio->io_parameter[0]); + iop[1] = le32_to_cpu(logio->io_parameter[1]); + switch (iop[0]) { + case LSC_SCODE_PORTID_USED: + data[0] = MBS_PORT_ID_USED; + data[1] = LSW(iop[1]); + break; + case LSC_SCODE_NPORT_USED: + data[0] = MBS_LOOP_ID_USED; + break; + case LSC_SCODE_CMD_FAILED: + if ((iop[1] & 0xff) == 0x05) { + data[0] = MBS_NOT_LOGGED_IN; + break; + } + /* Fall through. */ + 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 - comp=%x iop0=%x iop1=%x.\n", + fcport->vha->host_no, sp->handle, type, + le16_to_cpu(logio->comp_status), + 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); +} + /** * qla2x00_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -935,6 +1224,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); break; + case MBX_IOCB_TYPE: + qla2x00_mbx_iocb_entry(vha, rsp->req, + (struct mbx_entry *)pkt); default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1223,6 +1515,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); + scsi_set_resid(cp, resid); cp->result = DID_ERROR << 16; break; } @@ -1544,6 +1837,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_report_id_acquisition(vha, (struct vp_rpt_id_entry_24xx *)pkt); break; + case LOGINOUT_PORT_IOCB_TYPE: + qla24xx_logio_entry(vha, rsp->req, + (struct logio_entry_24xx *)pkt); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1723,8 +2020,10 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) vha = qla25xx_get_host(rsp); qla24xx_process_response_queue(vha, rsp); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - + if (!ha->mqenable) { + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + RD_REG_DWORD_RELAXED(®->hccr); + } spin_unlock_irq(&ha->hardware_lock); return IRQ_HANDLED; |