📄 isp_linux.c
字号:
while ((tmp = xqf) != NULL) { xqf = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; if (tmp == Cmnd) continue; tmp->result = DID_RESET << 16; /* * Get around silliness in midlayer. */ tmp->flags |= IS_RESETTING; if (tmp->scsi_done) (*tmp->scsi_done)(tmp); } while ((tmp = wq) != NULL) { wq = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; if (tmp == Cmnd) continue; tmp->result = DID_RESET << 16; /* * Get around silliness in midlayer. */ tmp->flags |= IS_RESETTING; if (tmp->scsi_done) (*tmp->scsi_done)(tmp); } while ((tmp = dq) != NULL) { dq = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; if (tmp == Cmnd) continue; tmp->result = DID_RESET << 16; /* * Get around silliness in midlayer. */ tmp->flags |= IS_RESETTING; if (tmp->scsi_done) (*tmp->scsi_done)(tmp); } Cmnd->result = DID_RESET << 16; return (SUCCESS);}#ifdef LINUX_ISP_TARGET_MODEstatic voidisp_attach_target(struct ispsoftc *isp){ int i; hba_register_t hba; hba.r_identity = isp; sprintf(hba.r_name, "isp"); hba.r_inst = isp->isp_unit; if (IS_DUALBUS(isp)) hba.r_buswidth = 2; else hba.r_buswidth = 1; hba.r_lunwidth = IS_FC(isp)? TM_MAX_LUN_FC : TM_MAX_LUN_SCSI; for (i = 0; i < NTGT_CMDS-1; i++) { isp->isp_osinfo.pool[i].cd_private = &isp->isp_osinfo.pool[i+1]; } isp->isp_osinfo.pending_t = NULL; isp->isp_osinfo.tfreelist = isp->isp_osinfo.pool; hba.r_action = (void (*)(int, void *))isp_taction; ISP_UNLKU_SOFTC(isp); ISP_PARENT_TARGET (QOUT_HBA_REG, &hba); ISP_LOCKU_SOFTC(isp);}static voidisp_detach_target(struct ispsoftc *isp){ tmd_cmd_t tmd; tmd.cd_hba = isp; tmd.cd_private = isp->isp_osinfo.hcb_token; ISP_PARENT_TARGET (QOUT_HBA_UNREG, &tmd);}static voidisp_taction(qact_e action, void *arg){ tmd_cmd_t *tmd = arg; struct ispsoftc *isp = (tmd != NULL)? tmd->cd_hba : NULL; switch (action) { case QIN_HBA_REG: { hba_register_t *hp = tmd->cd_data; isp_prt(isp, ISP_LOGINFO, "completed target registration"); isp->isp_osinfo.hcb = hp->r_action; isp->isp_osinfo.hcb_token = hp->r_identity; break; } case QIN_ENABLE: case QIN_DISABLE: { int r, bus, lun, tgt; bus = (int) tmd->cd_bus; lun = (int) tmd->cd_lun; tgt = (int) tmd->cd_tgt; r = isp_en_dis_lun(isp, (action == QIN_ENABLE)? 1 : 0, bus, tgt, lun); if (r) { tmd->cd_error = r; tmd->cd_lflags |= CDFL_ERROR; } break; } case QIN_TMD_CONT: isp_target_start_ctio(isp, tmd); break; case QIN_TMD_FIN: MEMZERO(tmd, sizeof (tmd_cmd_t)); ISP_LOCK_SOFTC(isp); tmd->cd_private = isp->isp_osinfo.tfreelist; isp->isp_osinfo.tfreelist = tmd; ISP_UNLK_SOFTC(isp); break; case QIN_HBA_UNREG: isp->isp_osinfo.hcb = NULL; break; default: break; }}static INLINE intnolunsenabled(struct ispsoftc *isp, int port){ int i, wbase, wend; if (IS_FC(isp)) { wbase = 0; wend = TM_MAX_LUN_FC >> 5; } else { if (port) { wend = TM_MAX_LUN_FC >> 5; wbase = wend >> 1; } else { wend = (TM_MAX_LUN_FC >> 5) >> 1; wbase = 0; } } for (i = wbase; i < wend; i++) { if (isp->isp_osinfo.lunbmap[i]) { return (0); } } return (1);}static voidisp_target_start_ctio(struct ispsoftc *isp, tmd_cmd_t *tmd){ void *qe; u_int16_t *hp, save_handle; u_int32_t *rp; u_int16_t nxti, optr; u_int8_t local[QENTRY_LEN]; /* * If the transfer length is zero, we have to be sending status. * If we're sending data, we have to have one and only one data * direction set. */ if (tmd->cd_xfrlen == 0) { if ((tmd->cd_hflags & CDFH_STSVALID) == 0) { isp_prt(isp, ISP_LOGERR, "CTIO, no data, and no status is wrong"); tmd->cd_error = -EINVAL; tmd->cd_lflags |= CDFL_ERROR; return; } } else { if ((tmd->cd_hflags & CDFH_DATA_MASK) == 0) { isp_prt(isp, ISP_LOGERR, "data CTIO with no direction is wrong"); tmd->cd_error = -EINVAL; tmd->cd_lflags |= CDFL_ERROR; return; } if ((tmd->cd_hflags & CDFH_DATA_MASK) == CDFH_DATA_MASK) { isp_prt(isp, ISP_LOGERR, "data CTIO with both directions is wrong"); tmd->cd_error = -EINVAL; tmd->cd_lflags |= CDFL_ERROR; return; } } tmd->cd_lflags &= ~CDFL_ERROR; MEMZERO(local, QENTRY_LEN); ISP_LOCK_SOFTC(isp); if (isp_getrqentry(isp, &nxti, &optr, &qe)) { isp_prt(isp, ISP_LOGWARN, "isp_target_start_ctio: request queue overflow"); tmd->cd_error = -ENOMEM; tmd->cd_lflags |= CDFL_ERROR; ISP_UNLK_SOFTC(isp); return; } /* * We're either moving data or completing a command here (or both). */ if (IS_FC(isp)) { ct2_entry_t *cto = (ct2_entry_t *) local; u_int16_t *ssptr = NULL; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; cto->ct_header.rqs_entry_count = 1; cto->ct_iid = tmd->cd_iid; if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) cto->ct_lun = tmd->cd_lun; else cto->ct_lun = 0; cto->ct_rxid = tmd->cd_tagval; if (cto->ct_rxid == 0) { isp_prt(isp, ISP_LOGERR, "a tagval of zero is not acceptable"); tmd->cd_error = -EINVAL; tmd->cd_lflags |= CDFL_ERROR; ISP_UNLK_SOFTC(isp); return; } cto->ct_flags = 0; if (tmd->cd_xfrlen == 0) { cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA | CT2_SENDSTATUS | CT2_CCINCR; ssptr = &cto->rsp.m1.ct_scsi_status; *ssptr = tmd->cd_scsi_status; if ((tmd->cd_hflags & CDFH_SNSVALID) != 0) { MEMCPY(cto->rsp.m1.ct_resp, tmd->cd_sense, QLTM_SENSELEN); cto->rsp.m1.ct_senselen = QLTM_SENSELEN; cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; } } else { cto->ct_flags |= CT2_FLAG_MODE0; if (tmd->cd_hflags & CDFH_DATA_IN) { cto->ct_flags |= CT2_DATA_IN; } else { cto->ct_flags |= CT2_DATA_OUT; } if (tmd->cd_hflags & CDFH_STSVALID) { ssptr = &cto->rsp.m0.ct_scsi_status; cto->ct_flags |= CT2_SENDSTATUS | CT2_CCINCR; cto->rsp.m0.ct_scsi_status = tmd->cd_scsi_status; if ((tmd->cd_hflags & CDFH_SNSVALID) && tmd->cd_scsi_status == SCSI_CHECK) { MEMCPY(cto->rsp.m0.ct_dataseg, tmd->cd_sense, QLTM_SENSELEN); cto->rsp.m0.ct_scsi_status |= CT2_SNSLEN_VALID; } } /* * We assume we'll transfer what we say we'll transfer. * Otherwise, the command is dead. */ tmd->cd_resid -= tmd->cd_xfrlen; } if (ssptr && tmd->cd_resid) { cto->ct_resid = tmd->cd_resid; *ssptr |= CT2_DATA_UNDER; } else { cto->ct_resid = 0; } isp_prt(isp, ISP_LOGTDEBUG0, "CTIO2[%x] ssts %x flags %x resid %d", cto->ct_rxid, tmd->cd_scsi_status, cto->ct_flags, cto->ct_resid); hp = &cto->ct_syshandle; rp = &cto->ct_resid; if (cto->ct_flags & CT2_SENDSTATUS) cto->ct_flags |= CT2_CCINCR; } else { ct_entry_t *cto = (ct_entry_t *) local; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_count = 1; cto->ct_iid = tmd->cd_iid; cto->ct_tgt = tmd->cd_tgt; cto->ct_lun = tmd->cd_lun; cto->ct_flags = 0; cto->ct_fwhandle = AT_GET_HANDLE(tmd->cd_tagval); if (AT_HAS_TAG(tmd->cd_tagval)) { cto->ct_tag_val = AT_GET_TAG(tmd->cd_tagval); cto->ct_flags |= CT_TQAE; } if (tmd->cd_lflags & CDFL_NODISC) { cto->ct_flags |= CT_NODISC; } if (tmd->cd_xfrlen == 0) { cto->ct_flags |= CT_NO_DATA | CT_SENDSTATUS; cto->ct_scsi_status = tmd->cd_scsi_status; cto->ct_resid = 0; } else { if (tmd->cd_hflags & CDFH_STSVALID) { cto->ct_flags |= CT_SENDSTATUS; } if (tmd->cd_hflags & CDFH_DATA_IN) { cto->ct_flags |= CT_DATA_IN; } else { cto->ct_flags |= CT_DATA_OUT; } /* * We assume we'll transfer what we say we'll transfer. * Otherwise, the command is dead. */ tmd->cd_resid -= tmd->cd_xfrlen; if (tmd->cd_hflags & CDFH_STSVALID) { cto->ct_resid = tmd->cd_resid; } } isp_prt(isp, ISP_LOGTDEBUG0, "CTIO[%x] ssts %x resid %d cd_hflags %x", AT_GET_HANDLE(tmd->cd_tagval), tmd->cd_scsi_status, tmd->cd_resid, tmd->cd_hflags); hp = &cto->ct_syshandle; rp = &cto->ct_resid; if (cto->ct_flags & CT_SENDSTATUS) cto->ct_flags |= CT_CCINCR; } if (isp_save_xs(isp, (XS_T *)tmd, hp)) { isp_prt(isp, ISP_LOGERR, "isp_target_start_ctio: No XFLIST pointers"); tmd->cd_error = -ENOMEM; tmd->cd_lflags |= CDFL_ERROR; ISP_UNLK_SOFTC(isp); tmd->cd_private = isp->isp_osinfo.hcb_token; (*isp->isp_osinfo.hcb)(QOUT_TMD_DONE, tmd); return; } /* * Call the dma setup routines for this entry (and any subsequent * CTIOs) if there's data to move, and then tell the f/w it's got * new things to play with. As with isp_start's usage of DMA setup, * any swizzling is done in the machine dependent layer. Because * of this, we put the request onto the queue area first in native * format. */ save_handle = *hp; switch (ISP_DMASETUP(isp, (XS_T *)tmd, (ispreq_t *) local, &nxti, optr)) { case CMD_QUEUED: ISP_ADD_REQUEST(isp, nxti); ISP_UNLK_SOFTC(isp); return; case CMD_EAGAIN: tmd->cd_error = -ENOMEM; tmd->cd_lflags |= CDFL_ERROR; isp_destroy_handle(isp, save_handle); break; case CMD_COMPLETE: tmd->cd_error = *rp; /* propagated back */ tmd->cd_lflags |= CDFL_ERROR; isp_destroy_handle(isp, save_handle); break; default: tmd->cd_error = -EFAULT; /* probably dma mapping failure */ tmd->cd_lflags |= CDFL_ERROR; isp_destroy_handle(isp, save_handle); break; } ISP_UNLK_SOFTC(isp); tmd->cd_private = isp->isp_osinfo.hcb_token; (*isp->isp_osinfo.hcb)(QOUT_TMD_DONE, tmd);}/* * Handle ATIO stuff that the generic code can't. * This means handling CDBs. */static intisp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep){ tmd_cmd_t *tmd; int status; /* * The firmware status (except for the QLTM_SVALID bit) * indicates why this ATIO was sent to us. * * If QLTM_SVALID is set, the firware has recommended Sense Data. * * If the DISCONNECTS DISABLED bit is set in the flags field, * we're still connected on the SCSI bus. */ status = aep->at_status; if ((status & ~QLTM_SVALID) == AT_PHASE_ERROR) { /* * Bus Phase Sequence error. We should have sense data * suggested by the f/w. I'm not sure quite yet what * to do about this. */ isp_prt(isp, ISP_LOGERR, "PHASE ERROR in atio"); isp_endcmd(isp, aep, SCSI_BUSY, 0); return (0); } if ((status & ~QLTM_SVALID) != AT_CDB) { isp_prt(isp, ISP_LOGERR, "bad atio (0x%x) leaked to platform", status); isp_endcmd(isp, aep, SCSI_BUSY, 0); return (0); } if ((tmd = isp->isp_osinfo.tfreelist) == NULL) { /* * We're out of resources. * * Because we can't autofeed sense data back with a command for * parallel SCSI, we can't give back a CHECK CONDITION. We'll give * back a QUEUE FULL or BUSY status instead. */ isp_prt(isp, ISP_LOGERR, "no ATIOS for lun %d from initiator %d on channel %d", aep->at_lun, GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid)); if (aep->at_flags & AT_TQAE) isp_endcmd(isp, aep, SCSI_QFULL, 0); else isp_endcmd(isp, aep, SCSI_BUSY, 0); return (0); } isp->isp_osinfo.tfreelist = tmd->cd_private; tmd->cd_lflags = CDFL_BUSY; tmd->cd_bus = GET_BUS_VAL(aep->at_iid); tmd->cd_iid = GET_IID_VAL(aep->at_iid); tmd->cd_tgt = aep->at_tgt; tmd->cd_lun = aep->at_lun; if (aep->at_flags & AT_NODISC) { tmd->cd_lflags |= CDFL_NODISC; } if (status & QLTM_SVALID) { MEMCPY(tmd->cd_sense, aep->at_sense, QLTM_SENSELEN); tmd->cd_lflags |= CDFL_SNSVALID; } MEMCPY(tmd->cd_cdb, aep->at_cdb, ATIO_CDBLEN); AT_MAKE_TAGID(tmd->cd_tagval, aep); tmd->cd_tagtype = aep->at_tag_type; tmd->cd_hba = isp; tmd->cd_data = NULL; tmd->cd_hflags = 0; tmd->cd_totlen = tmd->cd_resid = tmd->cd_xfrlen = tmd->cd_error = 0; tmd->cd_scsi_status = 0; isp_prt(isp, ISP_LOGTDEBUG1, "ATIO[%x] CDB=0x%x bus %d iid%d->lun%d tag 0x%x ttype 0x%x %s", aep->at_handle, aep->at_cdb[0] & 0xff, GET_BUS_VAL(aep->at_iid), GET_IID_VAL(aep->at_iid), aep->at_lun, aep->at_tag_val & 0xff, aep->at_tag_type, (aep->at_flags & AT_NODISC)? "nondisc" : "disconnecting"); if (isp->isp_osinfo.hcb == NULL) { isp_endcmd(isp, aep, SCSI_BUSY, 0); } else { tmd->cd_reserved[0] = QOUT_TMD_START; tmd->cd_private = isp->isp_osinfo.pending_t; isp->isp_osinfo.pending_t = tmd; } return (0);}static intisp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep){ tmd_cmd_t *tmd; int lun; /* * The firmware status (except for the QLTM_SVALID bit) * indicates why this ATIO was sent to us. * * If QLTM_SVALID is set, the firware has recommended Sense Data. */ if ((aep->at_status & ~QLTM_SVALID) != AT_CDB) { isp_prt(isp, ISP_LOGERR, "bad atio (0x%x) leaked to platform", aep->at_status); isp_endcmd(isp, aep, SCSI_BUSY, 0); return (0); } if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) lun = aep->at_scclun; else lun = aep->at_lun; /* * If we're out of resources, just send a QFULL status back.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -