📄 isp_linux.c
字号:
*/ if ((tmd = isp->isp_osinfo.tfreelist) == NULL) { isp_endcmd(isp, aep, SCSI_QFULL, 0); return (0); } tmd->cd_lflags = CDFL_BUSY; tmd->cd_iid = aep->at_iid; tmd->cd_tgt = ((fcparam *)isp->isp_param)->isp_loopid; tmd->cd_lun = lun; tmd->cd_bus = 0; MEMCPY(tmd->cd_cdb, aep->at_cdb, ATIO_CDBLEN); switch (aep->at_taskflags & ATIO2_TC_ATTR_MASK) { case ATIO2_TC_ATTR_SIMPLEQ: tmd->cd_tagtype = MSG_SIMPLE_Q_TAG; break; case ATIO2_TC_ATTR_HEADOFQ: tmd->cd_tagtype = MSG_HEAD_OF_Q_TAG; break; case ATIO2_TC_ATTR_ORDERED: tmd->cd_tagtype = MSG_ORDERED_Q_TAG; break; case ATIO2_TC_ATTR_ACAQ: /* ?? */ case ATIO2_TC_ATTR_UNTAGGED: default: tmd->cd_tagtype = 0; break; } tmd->cd_tagval = aep->at_rxid; tmd->cd_hba = isp; tmd->cd_data = NULL; tmd->cd_hflags = 0; tmd->cd_totlen = aep->at_datalen; tmd->cd_resid = tmd->cd_xfrlen = tmd->cd_error = 0; tmd->cd_scsi_status = 0; if ((isp->isp_dblev & ISP_LOGTDEBUG0) || isp->isp_osinfo.hcb == NULL) { isp_prt(isp, ISP_LOGALL, "ATIO2[%x] CDB=0x%x iid %d for lun %d tcode 0x%x dlen %d", aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, lun, aep->at_taskcodes, aep->at_datalen); } if (isp->isp_osinfo.hcb == NULL) { if (aep->at_cdb[0] == INQUIRY && lun == 0) { if (aep->at_cdb[1] == 0 && aep->at_cdb[2] == 0) { static u_int8_t inqdata[] = { DEFAULT_DEVICE_TYPE, 0x0, 0x2, 0x2, 32, 0, 0, 0x40, 'L', 'I', 'N', 'U', 'X', ' ', ' ', ' ', 'T', 'A', 'R', 'G', 'E', 'T', ' ', 'D', 'D', 'E', 'V', 'I', 'C', 'E', ' ', ' ', '0', '0', '0', '1' }; struct scatterlist single, *dp = &single; dp->address = inqdata; dp->alt_address = NULL; dp->length = sizeof (inqdata); tmd->cd_data = dp; tmd->cd_resid = tmd->cd_xfrlen = sizeof (inqdata); tmd->cd_hflags |= CDFH_DATA_IN|CDFH_STSVALID; ISP_DROP_LK_SOFTC(isp); isp_target_start_ctio(isp, tmd); ISP_IGET_LK_SOFTC(isp); } else { /* * Illegal field in CDB * 0x24 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK */ isp_endcmd(isp, aep, 0x24005102, 0); } } else if (lun == 0) { /* * Not Ready, Cause Not Reportable * * 0x4 << 24 | 0x2 << 12 | ECMD_SVALID | SCSI_CHECK */ isp_endcmd(isp, aep, 0x04002102, 0); } else { /* * Logical Unit Not Supported: * 0x25 << 24 | 0x5 << 12 | ECMD_SVALID | SCSI_CHECK */ isp_endcmd(isp, aep, 0x25005102, 0); } MEMZERO(tmd, sizeof (tmd_cmd_t)); return (0); } tmd->cd_reserved[0] = QOUT_TMD_START; isp->isp_osinfo.tfreelist = tmd->cd_private; tmd->cd_private = isp->isp_osinfo.pending_t; isp->isp_osinfo.pending_t = tmd; return (0);}static intisp_handle_platform_ctio(struct ispsoftc *isp, void *arg){ tmd_cmd_t *tmd; int sentstatus, ok, resid = 0, sts; /* * CTIO and CTIO2 are close enough.... */ tmd = (tmd_cmd_t *) isp_find_xs(isp, ((ct_entry_t *)arg)->ct_syshandle); if (tmd == NULL) { isp_prt(isp, ISP_LOGERR, "isp_handle_platform_ctio: null tmd"); return (0); } isp_destroy_handle(isp, ((ct_entry_t *)arg)->ct_syshandle); if (IS_FC(isp)) { ct2_entry_t *ct = arg; sentstatus = ct->ct_flags & CT2_SENDSTATUS; if (sentstatus) { tmd->cd_lflags |= CDFL_SENTSTATUS; } sts = ct->ct_status & ~QLTM_SVALID; ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; if (ok && sentstatus && (tmd->cd_hflags & CDFH_SNSVALID)) { tmd->cd_lflags |= CDFL_SENTSENSE; } isp_prt(isp, ISP_LOGTDEBUG1, "CTIO2[%x] sts 0x%x flg 0x%x sns %d %s", ct->ct_rxid, ct->ct_status, ct->ct_flags, (tmd->cd_lflags & CDFL_SENTSENSE) != 0, sentstatus? "FIN" : "MID"); if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { resid = ct->ct_resid; } } else { ct_entry_t *ct = arg; sts = ct->ct_status & ~QLTM_SVALID; sentstatus = ct->ct_flags & CT_SENDSTATUS; if (sentstatus) { tmd->cd_lflags |= CDFL_SENTSTATUS; } ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; if (ok && sentstatus && (tmd->cd_hflags & CDFH_SNSVALID)) { tmd->cd_lflags |= CDFL_SENTSENSE; } isp_prt(isp, ISP_LOGTDEBUG1, "CTIO[%x] tag %x iid %x tgt %d lun %d sts 0x%x flg %x %s", ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_tgt, ct->ct_lun, ct->ct_status, ct->ct_flags, sentstatus? "FIN" : "MID"); if (ct->ct_status & QLTM_SVALID) { char *sp = (char *)ct; sp += CTIO_SENSE_OFFSET; MEMCPY(tmd->cd_sense, sp, QLTM_SENSELEN); tmd->cd_lflags |= CDFL_SNSVALID; } if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { resid = ct->ct_resid; } } tmd->cd_resid += resid; /* * We're here either because intermediate data transfers are done * and/or the final status CTIO (which may have joined with a * Data Transfer) is done. * * In any case, for this platform, the upper layers figure out * what to do next, so all we do here is collect status and * pass information along. */ isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO done (resid %d)", (sentstatus)? " FINAL " : "MIDTERM ", tmd->cd_resid); if (!ok) { isp_prt(isp, ISP_LOGERR, "CTIO ended with badstate (0x%x)", sts); tmd->cd_lflags |= CDFL_ERROR; tmd->cd_error = -EIO; isp_target_putback_atio(isp, tmd); } else { isp_complete_ctio(isp, tmd); } return (0);}static voidisp_target_putback_atio(struct ispsoftc *isp, tmd_cmd_t *tmd){ u_int16_t nxti; u_int8_t local[QENTRY_LEN]; void *qe; if (isp_getrqentry(isp, &nxti, NULL, &qe)) { isp_prt(isp, ISP_LOGWARN, "isp_target_putback_atio: Request Queue Overflow"); /* XXXX */ isp_complete_ctio(isp, tmd); return; } MEMZERO(local, sizeof (local)); if (IS_FC(isp)) { at2_entry_t *at = (at2_entry_t *) local; at->at_header.rqs_entry_type = RQSTYPE_ATIO2; at->at_header.rqs_entry_count = 1; if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) at->at_scclun = (uint16_t) tmd->cd_lun; else at->at_lun = (uint8_t) tmd->cd_lun; at->at_status = CT_OK; at->at_rxid = tmd->cd_tagval; isp_put_atio2(isp, at, qe); } else { at_entry_t *at = (at_entry_t *)local; at->at_header.rqs_entry_type = RQSTYPE_ATIO; at->at_header.rqs_entry_count = 1; at->at_iid = tmd->cd_iid; at->at_iid |= tmd->cd_bus << 7; at->at_tgt = tmd->cd_tgt; at->at_lun = tmd->cd_lun; at->at_status = CT_OK; at->at_tag_val = AT_GET_TAG(tmd->cd_tagval); at->at_handle = AT_GET_HANDLE(tmd->cd_tagval); isp_put_atio(isp, at, qe); } ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe); ISP_ADD_REQUEST(isp, nxti); isp_complete_ctio(isp, tmd);}static voidisp_complete_ctio(struct ispsoftc *isp, tmd_cmd_t *tmd){ if (isp->isp_osinfo.hcb == NULL) { isp_prt(isp, ISP_LOGWARN, "nobody to tell about completing command"); MEMZERO(tmd, sizeof (tmd_cmd_t)); tmd->cd_private = isp->isp_osinfo.tfreelist; isp->isp_osinfo.tfreelist = tmd; } else { tmd->cd_reserved[0] = QOUT_TMD_DONE; tmd->cd_private = isp->isp_osinfo.pending_t; isp->isp_osinfo.pending_t = tmd; }}static intisp_en_dis_lun(struct ispsoftc *isp, int enable, int bus, int tgt, int lun){ DECLARE_MUTEX_LOCKED(rsem); u_int16_t rstat; int rv, enabled, cmd; /* * First, we can't do anything unless we have an upper * level target driver to route commands to. */ if (isp->isp_osinfo.hcb == NULL) { return (-EINVAL); } /* * Second, check for sanity of enable argument. */ enabled = ((isp->isp_osinfo.tmflags & (1 << bus)) != 0); if (enable == 0 && enabled == 0) { return (-EINVAL); } /* * Third, check to see if we're enabling on fibre channel * and don't yet have a notion of who the heck we are (no * loop yet). */ if (IS_FC(isp) && !enabled) { ISP_LOCK_SOFTC(isp); if ((isp->isp_role & ISP_ROLE_TARGET) == 0) { isp->isp_role |= ISP_ROLE_TARGET; if (isp_drain_reset(isp, "lun enables")) { return (-EIO); } } ISP_UNLK_SOFTC(isp); SEND_THREAD_EVENT(isp, ISP_THREAD_FC_RESCAN, 1); } /* * If this is a wildcard target, select our initiator * id/loop id for use as what we enable as. */ if (tgt == -1) { if (IS_FC(isp)) { tgt = ((fcparam *)isp->isp_param)->isp_loopid; } else { tgt = ((sdparam *)isp->isp_param)->isp_initiator_id; } } /* * Do some sanity checking on lun arguments. */ if (lun < 0 || lun >= (IS_FC(isp)? TM_MAX_LUN_FC : TM_MAX_LUN_SCSI)) { return (-EINVAL); } /* * Snag the semaphore on the return state value on enables/disables. */ if (down_interruptible(&isp->isp_osinfo.tgt_inisem)) { return (-EINTR); } if (enable && LUN_BTST(isp, bus, lun)) { up(&isp->isp_osinfo.tgt_inisem); return (-EEXIST); } if (!enable && !LUN_BTST(isp, bus, lun)) { up(&isp->isp_osinfo.tgt_inisem); return (-NODEV); } if (enable && nolunsenabled(isp, bus)) { int av = (bus << 31) | ENABLE_TARGET_FLAG; ISP_LOCK_SOFTC(isp); rv = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); ISP_UNLK_SOFTC(isp); if (rv) { up(&isp->isp_osinfo.tgt_inisem); return (-EIO); } } ISP_LOCK_SOFTC(isp); isp->isp_osinfo.rsemap = &rsem; if (enable) { u_int32_t seq = isp->isp_osinfo.rollinfo++; int n, ulun = lun; cmd = RQSTYPE_ENABLE_LUN; n = DFLT_INOT_CNT; if (IS_FC(isp) && lun != 0) { cmd = RQSTYPE_MODIFY_LUN; n = 0; /* * For SCC firmware, we only deal with setting * (enabling or modifying) lun 0. */ ulun = 0; } rstat = LUN_ERR; if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, DFLT_CMND_CNT, n, seq)) { isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); goto out; } ISP_UNLK_SOFTC(isp); down(isp->isp_osinfo.rsemap); ISP_LOCK_SOFTC(isp); isp->isp_osinfo.rsemap = NULL; rstat = isp->isp_osinfo.rstatus; if (rstat != LUN_OK) { isp_prt(isp, ISP_LOGERR, "MODIFY/ENABLE LUN returned 0x%x", rstat); goto out; } } else { int n, ulun = lun; u_int32_t seq; rstat = LUN_ERR; seq = isp->isp_osinfo.rollinfo++; cmd = -RQSTYPE_MODIFY_LUN; n = DFLT_INOT_CNT; if (IS_FC(isp) && lun != 0) { n = 0; /* * For SCC firmware, we only deal with setting * (enabling or modifying) lun 0. */ ulun = 0; } if (isp_lun_cmd(isp, cmd, bus, tgt, ulun, DFLT_CMND_CNT, n, seq)) { isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); goto out; } ISP_UNLK_SOFTC(isp); down(isp->isp_osinfo.rsemap); ISP_LOCK_SOFTC(isp); isp->isp_osinfo.rsemap = NULL; rstat = isp->isp_osinfo.rstatus; if (rstat != LUN_OK) { isp_prt(isp, ISP_LOGERR, "MODIFY LUN returned 0x%x", rstat); goto out; } if (IS_FC(isp) && lun) { goto out; } seq = isp->isp_osinfo.rollinfo++; isp->isp_osinfo.rsemap = &rsem; rstat = LUN_ERR; cmd = -RQSTYPE_ENABLE_LUN; if (isp_lun_cmd(isp, cmd, bus, tgt, lun, 0, 0, seq)) { isp_prt(isp, ISP_LOGERR, "isp_lun_cmd failed"); goto out; } ISP_UNLK_SOFTC(isp); down(isp->isp_osinfo.rsemap); ISP_LOCK_SOFTC(isp); isp->isp_osinfo.rsemap = NULL; rstat = isp->isp_osinfo.rstatus; if (rstat != LUN_OK) { isp_prt(isp, ISP_LOGERR, "DISABLE LUN returned 0x%x", rstat); goto out; } }out: if (rstat != LUN_OK) { isp_prt(isp, ISP_LOGERR, "lun %d %sable failed", lun, (enable) ? "en" : "dis"); ISP_UNLK_SOFTC(isp); up(&isp->isp_osinfo.tgt_inisem); return (-EIO); } else { isp_prt(isp, ISP_LOGINFO, "lun %d now %sabled for target mode on channel %d", lun, (enable)? "en" : "dis", bus); if (enable == 0) { LUN_BCLR(isp, bus, lun); if (nolunsenabled(isp, bus)) { int av = bus << 31; rv = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); if (rv) { isp_prt(isp, ISP_LOGERR, "failed to disable target mode on channel %d", bus); /* but proceed */ ISP_UNLK_SOFTC(isp); return (-EIO); } isp->isp_osinfo.tmflags &= ~(1 << bus); isp->isp_role &= ~ISP_ROLE_TARGET; if (IS_FC(isp)) { if (isplinux_drain_reset(isp, "lun disables")) { return (-EIO); } if ((isp->isp_role & ISP_ROLE_INITIATOR) != 0) { ISP_UNLK_SOFTC(isp); SEND_THREAD_EVENT(isp, ISP_THREAD_FC_RESCAN, 1); ISP_LOCK_SOFTC(isp); } } } } else { isp->isp_osinfo.tmflags |= (1 << bus); LUN_BSET(isp, bus, lun); } ISP_UNLK_SOFTC(isp); up(&isp->isp_osinfo.tgt_inisem); return (0); }}#endifintisp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg){ switch (cmd) { case ISPASYNC_NEW_TGT_PARAMS: if (IS_SCSI(isp)) { sdparam *sdp = isp->isp_param; char *wt; int mhz, flags, bus, tgt, period; tgt = *((int *) arg); bus = (tgt >> 16) & 0xffff; tgt &= 0xffff; sdp += bus; flags = sdp->isp_devparam[tgt].actv_flags; period = sdp->isp_devparam[tgt].actv_period; if ((flags & DPARM_SYNC) && period && (sdp->isp_devparam[tgt].actv_offset) != 0) { if (sdp->isp_lvdmode || period < 0xc) { switch (period) { case 0x9: mhz = 80; break; case 0xa: mhz = 40; break; case 0xb: mhz = 33; break; case 0xc: mhz = 25; break; default: mhz = 1000 / (period * 4); break; } } else { mhz = 1000 / (period * 4); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -