📄 isp.c
字号:
if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { PRINTF("%s: bad frame length (%d) from NVRAM- using %d\n", isp->isp_name, fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN); icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; } icbp->icb_maxalloc = fcp->isp_maxalloc; if (icbp->icb_maxalloc < 16) { PRINTF("%s: bad maximum allocation (%d)- using 16\n", isp->isp_name, fcp->isp_maxalloc); icbp->icb_maxalloc = 16; } icbp->icb_execthrottle = fcp->isp_execthrottle; if (icbp->icb_execthrottle < 1) { PRINTF("%s: bad execution throttle of %d- using 16\n", isp->isp_name, fcp->isp_execthrottle); icbp->icb_execthrottle = 16; } icbp->icb_retry_delay = fcp->isp_retry_delay; icbp->icb_retry_count = fcp->isp_retry_count; icbp->icb_hardaddr = loopid; if (fcp->isp_wwn) { MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwn); if (icbp->icb_fwoptions & ICBOPT_USE_PORTNAME) { u_int64_t portname = fcp->isp_wwn | (2LL << 56); MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, portname); } } else { fcp->isp_fwoptions &= ~(ICBOPT_USE_PORTNAME|ICBOPT_FULL_LOGIN); } icbp->icb_rqstqlen = RQUEST_QUEUE_LEN; icbp->icb_rsltqlen = RESULT_QUEUE_LEN; icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_LSW(isp->isp_rquest_dma); icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_MSW(isp->isp_rquest_dma); icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_LSW(isp->isp_result_dma); icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_MSW(isp->isp_result_dma); MemoryBarrier(); for (count = 0; count < 10; count++) { mbs.param[0] = MBOX_INIT_FIRMWARE; mbs.param[1] = 0; mbs.param[2] = DMA_MSW(fcp->isp_scdma); mbs.param[3] = DMA_LSW(fcp->isp_scdma); mbs.param[4] = 0; mbs.param[5] = 0; mbs.param[6] = 0; mbs.param[7] = 0; isp_mboxcmd(isp, &mbs); switch (mbs.param[0]) { case MBOX_COMMAND_COMPLETE: count = 10; break; case ASYNC_PDB_CHANGED: isp_mark_getpdb_all(isp); /* FALL THROUGH */ case ASYNC_LIP_OCCURRED: case ASYNC_LOOP_UP: case ASYNC_LOOP_DOWN: case ASYNC_LOOP_RESET: case ASYNC_CHANGE_NOTIFY: if (count > 9) { PRINTF("%s: too many retries to get going- " "giving up\n", isp->isp_name); return; } break; default: PRINTF("%s: INIT FIRMWARE failed\n", isp->isp_name); return; } } isp->isp_reqidx = isp->isp_reqodx = 0; isp->isp_residx = 0; isp->isp_sendmarker = 1; /* * Whatever happens, we're now committed to being here. */ isp->isp_state = ISP_INITSTATE; fcp->isp_fwstate = FW_CONFIG_WAIT; isp_mark_getpdb_all(isp);#ifdef ISP_TARGET_MODE if (isp_modify_lun(isp, 0, 1, 1)) { PRINTF("%s: failed to enable target mode\n", isp->isp_name); }#endif}/* * Fibre Channel Support- get the port database for the id. * * Locks are held before coming here. Return 0 if success, * else failure. */static voidisp_mark_getpdb_all(isp) struct ispsoftc *isp;{ isp_pdb_t *p; fcparam *fcp = (fcparam *) isp->isp_param; for (p = &fcp->isp_pdb[0]; p < &fcp->isp_pdb[MAX_FC_TARG]; p++) { p->pdb_options = INVALID_PDB_OPTIONS; }}static intisp_getpdb(isp, id, pdbp) struct ispsoftc *isp; int id; isp_pdb_t *pdbp;{ fcparam *fcp = (fcparam *) isp->isp_param; mbreg_t mbs; mbs.param[0] = MBOX_GET_PORT_DB; mbs.param[1] = id << 8; mbs.param[2] = DMA_MSW(fcp->isp_scdma); mbs.param[3] = DMA_LSW(fcp->isp_scdma); /* * Unneeded. For the 2100, except for initializing f/w, registers * 4/5 have to not be written to. * mbs.param[4] = 0; * mbs.param[5] = 0; * */ mbs.param[6] = 0; mbs.param[7] = 0; isp_mboxcmd(isp, &mbs); switch (mbs.param[0]) { case MBOX_COMMAND_COMPLETE: MemoryBarrier(); MEMCPY(pdbp, fcp->isp_scratch, sizeof (isp_pdb_t)); break; case MBOX_HOST_INTERFACE_ERROR: PRINTF("%s: DMA error getting port database\n", isp->isp_name); return (-1); case MBOX_COMMAND_PARAM_ERROR: /* Not Logged In */ IDPRINTF(3, ("%s: Comand Param Error on Get Port Database\n", isp->isp_name)); return (-1); default: PRINTF("%s: error 0x%x getting port database for ID %d\n", isp->isp_name, mbs.param[0], id); return (-1); } return (0);}/* * Make sure we have good FC link and know our Loop ID. */static intisp_fclink_test(isp, waitdelay) struct ispsoftc *isp; int waitdelay;{ mbreg_t mbs; int count; u_int8_t lwfs; fcparam *fcp; fcp = isp->isp_param; /* * Wait up to N microseconds for F/W to go to a ready state. */ lwfs = FW_CONFIG_WAIT; for (count = 0; count < waitdelay; count += 100) { isp_fw_state(isp); if (lwfs != fcp->isp_fwstate) { PRINTF("%s: Firmware State %s -> %s\n", isp->isp_name, isp2100_fw_statename((int)lwfs), isp2100_fw_statename((int)fcp->isp_fwstate)); lwfs = fcp->isp_fwstate; } if (fcp->isp_fwstate == FW_READY) { break; } SYS_DELAY(100); /* wait 100 microseconds */ } /* * If we haven't gone to 'ready' state, return. */ if (fcp->isp_fwstate != FW_READY) { return (-1); } /* * Get our Loop ID (if possible). We really need to have it. */ mbs.param[0] = MBOX_GET_LOOP_ID; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { PRINTF("%s: GET LOOP ID failed\n", isp->isp_name); return (-1); } fcp->isp_loopid = mbs.param[1]; fcp->isp_alpa = mbs.param[2]; PRINTF("%s: Loop ID %d, ALPA 0x%x\n", isp->isp_name, fcp->isp_loopid, fcp->isp_alpa); return (0);}/* * Start a command. Locking is assumed done in the caller. */int32_tispscsicmd(xs) ISP_SCSI_XFER_T *xs;{ struct ispsoftc *isp; u_int8_t iptr, optr; union { ispreq_t *_reqp; ispreqt2_t *_t2reqp; } _u;#define reqp _u._reqp#define t2reqp _u._t2reqp#define UZSIZE max(sizeof (ispreq_t), sizeof (ispreqt2_t)) int i, rqidx; XS_INITERR(xs); isp = XS_ISP(xs); if (isp->isp_state != ISP_RUNSTATE) { PRINTF("%s: adapter not ready\n", isp->isp_name); XS_SETERR(xs, HBA_BOTCH); return (CMD_COMPLETE); } /* * We *could* do the different sequence type that has close * to the whole Queue Entry for the command... */ if (XS_CDBLEN(xs) > (IS_FC(isp) ? 16 : 12) || XS_CDBLEN(xs) == 0) { PRINTF("%s: unsupported cdb length (%d, CDB[0]=0x%x)\n", isp->isp_name, XS_CDBLEN(xs), XS_CDBP(xs)[0]); XS_SETERR(xs, HBA_BOTCH); return (CMD_COMPLETE); } /* * Check to see whether we have good firmware state still or * need to refresh our port database for this target. */ if (IS_FC(isp)) { fcparam *fcp = isp->isp_param; isp_pdb_t *pdbp = &fcp->isp_pdb[XS_TGT(xs)]; /* * Check for f/w being in ready state. Well, okay, * our cached copy of it... */ if (fcp->isp_fwstate != FW_READY) { if (isp_fclink_test(isp, FC_FW_READY_DELAY)) { XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); } } /* * Refresh our port database if needed. */ if (pdbp->pdb_options == INVALID_PDB_OPTIONS) { if (isp_getpdb(isp, XS_TGT(xs), pdbp) == 0) { isp_async(isp, ISPASYNC_PDB_CHANGE_COMPLETE, (void *) (long) XS_TGT(xs)); } } } /* * Next check to see if any HBA or Device * parameters need to be updated. */ if (isp->isp_update != 0) { isp_update(isp); } optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4); iptr = isp->isp_reqidx; reqp = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); if (iptr == optr) { IDPRINTF(2, ("%s: Request Queue Overflow\n", isp->isp_name)); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } /* * Now see if we need to synchronize the ISP with respect to anything. * We do dual duty here (cough) for synchronizing for busses other * than which we got here to send a command to. */ if (isp->isp_sendmarker) { u_int8_t niptr, n = (IS_12X0(isp)? 2: 1); /* * Check ports to send markers for... */ for (i = 0; i < n; i++) { if ((isp->isp_sendmarker & (1 << i)) == 0) { continue; } MEMZERO((void *) reqp, sizeof (*reqp)); reqp->req_header.rqs_entry_count = 1; reqp->req_header.rqs_entry_type = RQSTYPE_MARKER; reqp->req_modifier = SYNC_ALL; ISP_SBUSIFY_ISPHDR(isp, &reqp->req_header); reqp->req_target = i << 7; ISP_SBUSIFY_ISPREQ(isp, reqp); /* * Unconditionally update the input pointer anyway. */ ISP_WRITE(isp, INMAILBOX4, iptr); isp->isp_reqidx = iptr; niptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); if (niptr == optr) { IDPRINTF(2, ("%s: Request Queue Overflow+\n", isp->isp_name)); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } reqp = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); iptr = niptr; } } MEMZERO((void *) reqp, UZSIZE); reqp->req_header.rqs_entry_count = 1; if (isp->isp_type & ISP_HA_FC) { reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS; } else { reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST; } reqp->req_header.rqs_flags = 0; reqp->req_header.rqs_seqno = isp->isp_seqno++; ISP_SBUSIFY_ISPHDR(isp, &reqp->req_header); for (rqidx = 0; rqidx < RQUEST_QUEUE_LEN; rqidx++) { if (isp->isp_xflist[rqidx] == NULL) break; } if (rqidx == RQUEST_QUEUE_LEN) { IDPRINTF(2, ("%s: out of xflist pointers\n", isp->isp_name)); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } else { /* * Never have a handle that is zero, so * set req_handle off by one. */ isp->isp_xflist[rqidx] = xs; reqp->req_handle = rqidx+1; } if (isp->isp_type & ISP_HA_FC) { /* * See comment in isp_intr */ XS_RESID(xs) = 0; /* * Fibre Channel always requires some kind of tag. * If we're marked as "Can't Tag", just do simple * instead of ordered tags. It's pretty clear to me * that we shouldn't do head of queue tagging in * this case. */ if (XS_CANTAG(xs)) { t2reqp->req_flags = XS_KINDOF_TAG(xs); } else { t2reqp->req_flags = REQFLAG_STAG; } } else { sdparam *sdp = (sdparam *)isp->isp_param; if ((sdp->isp_devparam[XS_TGT(xs)].cur_dflags & DPARM_TQING) && XS_CANTAG(xs)) { reqp->req_flags = XS_KINDOF_TAG(xs); } else { reqp->req_flags = 0; } } reqp->req_target = XS_TGT(xs) | (XS_CHANNEL(xs) << 7); if (isp->isp_type & ISP_HA_SCSI) { reqp->req_lun_trn = XS_LUN(xs); reqp->req_cdblen = XS_CDBLEN(xs); } else {#ifdef ISP2100_SCCLUN reqp->req_scclun = XS_LUN(xs);#else reqp->req_lun_trn = XS_LUN(xs);#endif } MEMCPY(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs)); IDPRINTF(5, ("%s(%d.%d.%d): START%d cmd 0x%x datalen %d\n", isp->isp_name, XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), reqp->req_header.rqs_seqno, reqp->req_cdb[0], XS_XFRLEN(xs))); reqp->req_time = XS_TIME(xs) / 1000; if (reqp->req_time == 0 && XS_TIME(xs)) reqp->req_time = 1; /* * Always give a bit more leeway to commands after a bus reset. * XXX: DOES NOT DISTINGUISH WHICH PORT MAY HAVE BEEN SYNCED */ if (isp->isp_sendmarker && reqp->req_time < 5) reqp->req_time = 5; i = ISP_DMASETUP(isp, xs, reqp, &iptr, optr); if (i != CMD_QUEUED) { /* * Take memory of it away... */ isp->isp_xflist[rqidx] = NULL; /* * dmasetup sets actual error in packet, and * return what we were given to return. */ return (i); } XS_SETERR(xs, HBA_NOERROR); ISP_SBUSIFY_ISPREQ(isp, reqp); MemoryBarrier(); ISP_WRITE(isp, INMAILBOX4, iptr); isp->isp_reqidx = iptr; isp->isp_nactive++; if (isp->isp_sendmarker) isp->isp_sendmarker = 0; return (CMD_QUEUED);#undef reqp#undef t2reqp}/* * isp control * Locks (ints blocked) assumed held. */intisp_control(isp, ctl, arg) struct ispsoftc *isp; ispctl_t ctl; void *arg;{ ISP_SCSI_XFER_T *xs; mbreg_t mbs; int i, bus, tgt; switch (ctl) { default: PRINTF("%s: isp_control unknown control op %x\n", isp->isp_name, ctl); break; case ISPCTL_RESET_BUS: /* * Issue a bus reset. */ mbs.param[0] = MBOX_BUS_RESET; if (isp->isp_type & ISP_HA_SCSI) { mbs.param[1] = ((sdparam *) isp->isp_param)->isp_bus_reset_delay; if (mbs.param[1] < 2) mbs.param[1] = 2; } else { /* * Unparameterized. */ mbs.param[1] = 5; } bus = *((int *) arg); mbs.param[2] = bus; isp->isp_sendmarker = 1 << bus; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_dumpregs(isp, "isp_control SCSI bus reset failed"); break; } PRINTF("%s: driver initiated bus reset of bus %d\n", isp->isp_name, bus); return (0); case ISPCTL_RESET_DEV: tgt = (*((int *) arg)) & 0xffff; bus = (*((int *) arg)) >> 16; mbs.param[0] = MBOX_ABORT_TARGET; mbs.param[1] = (tgt << 8) | (bus << 15); mbs.param[2] = 3; /* 'delay', in seconds */ isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_dumpregs(isp, "Target Reset Failed"); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -