📄 isp.c
字号:
} PRINTF("%s: Target %d on Bus %d Reset Succeeded\n", isp->isp_name, tgt, bus); isp->isp_sendmarker = 1 << bus; return (0); case ISPCTL_ABORT_CMD: xs = (ISP_SCSI_XFER_T *) arg; for (i = 0; i < RQUEST_QUEUE_LEN; i++) { if (xs == isp->isp_xflist[i]) { break; } } if (i == RQUEST_QUEUE_LEN) { PRINTF("%s: isp_control- cannot find command to abort " "in active list\n", isp->isp_name); break; } mbs.param[0] = MBOX_ABORT;#ifdef ISP2100_SCCLUN if (isp->isp_type & ISP_HA_FC) { mbs.param[1] = XS_TGT(xs) << 8; mbs.param[4] = 0; mbs.param[5] = 0; mbs.param[6] = XS_LUN(xs); } else { mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs); }#else mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs);#endif /* * XXX: WHICH BUS? */ mbs.param[2] = (i+1) >> 16; mbs.param[3] = (i+1) & 0xffff; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { PRINTF("%s: isp_control MBOX_ABORT failure (code %x)\n", isp->isp_name, mbs.param[0]); break; } PRINTF("%s: command for target %d lun %d was aborted\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs)); return (0); case ISPCTL_UPDATE_PARAMS: isp_update(isp); return (0); case ISPCTL_FCLINK_TEST: return (isp_fclink_test(isp, FC_FW_READY_DELAY)); } return (-1);}/* * Interrupt Service Routine(s). * * External (OS) framework has done the appropriate locking, * and the locking will be held throughout this function. */intisp_intr(arg) void *arg;{ ISP_SCSI_XFER_T *complist[RESULT_QUEUE_LEN], *xs; struct ispsoftc *isp = arg; u_int8_t iptr, optr; u_int16_t isr, sema; int i, nlooked = 0, ndone = 0; /* * Well, if we've disabled interrupts, we may get a case where * isr isn't set, but sema is. */ isr = ISP_READ(isp, BIU_ISR); sema = ISP_READ(isp, BIU_SEMA) & 0x1; IDPRINTF(5, ("%s: isp_intr isr %x sem %x\n", isp->isp_name, isr, sema)); if (IS_FC(isp)) { if (isr == 0 || (isr & BIU2100_ISR_RISC_INT) == 0) { if (isr) { IDPRINTF(4, ("%s: isp_intr isr=%x\n", isp->isp_name, isr)); } return (0); } } else { if (isr == 0 || (isr & BIU_ISR_RISC_INT) == 0) { if (isr) { IDPRINTF(4, ("%s: isp_intr isr=%x\n", isp->isp_name, isr)); } return (0); } } if (isp->isp_state != ISP_RUNSTATE) { IDPRINTF(3, ("%s: interrupt (isr=%x,sema=%x) when not ready\n", isp->isp_name, isr, sema)); ISP_WRITE(isp, INMAILBOX5, ISP_READ(isp, OUTMAILBOX5)); ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); ISP_WRITE(isp, BIU_SEMA, 0); ENABLE_INTS(isp); return (1); } if (sema) { u_int16_t mbox = ISP_READ(isp, OUTMAILBOX0); if (mbox & 0x4000) { IDPRINTF(3, ("%s: Command Mbox 0x%x\n", isp->isp_name, mbox)); } else { u_int32_t fhandle = isp_parse_async(isp, (int) mbox); IDPRINTF(3, ("%s: Async Mbox 0x%x\n", isp->isp_name, mbox)); if (fhandle > 0) { xs = (void *)isp->isp_xflist[fhandle - 1]; isp->isp_xflist[fhandle - 1] = NULL; /* * Since we don't have a result queue entry * item, we must believe that SCSI status is * zero and that all data transferred. */ XS_RESID(xs) = 0; XS_STS(xs) = 0; if (XS_XFRLEN(xs)) { ISP_DMAFREE(isp, xs, fhandle - 1); } if (isp->isp_nactive > 0) isp->isp_nactive--; XS_CMD_DONE(xs); } } ISP_WRITE(isp, BIU_SEMA, 0); ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); ENABLE_INTS(isp); return (1); } /* * You *must* read OUTMAILBOX5 prior to clearing the RISC interrupt. */ optr = isp->isp_residx; iptr = ISP_READ(isp, OUTMAILBOX5); ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); if (optr == iptr) { IDPRINTF(4, ("why intr? isr %x iptr %x optr %x\n", isr, optr, iptr)); } while (optr != iptr) { ispstatusreq_t *sp; u_int8_t oop; int buddaboom = 0; sp = (ispstatusreq_t *) ISP_QUEUE_ENTRY(isp->isp_result, optr); oop = optr; optr = ISP_NXT_QENTRY(optr, RESULT_QUEUE_LEN); nlooked++; MemoryBarrier(); ISP_SBUSIFY_ISPHDR(isp, &sp->req_header); if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE) { if (isp_handle_other_response(isp, sp, &optr) == 0) { ISP_WRITE(isp, INMAILBOX5, optr); continue; } /* * It really has to be a bounced request just copied * from the request queue to the response queue. If * not, something bad has happened. */ if (sp->req_header.rqs_entry_type != RQSTYPE_REQUEST) { ISP_WRITE(isp, INMAILBOX5, optr); PRINTF("%s: not RESPONSE in RESPONSE Queue " "(type 0x%x) @ idx %d (next %d)\n", isp->isp_name, sp->req_header.rqs_entry_type, oop, optr); continue; } buddaboom = 1; } if (sp->req_header.rqs_flags & 0xf) {#define _RQS_OFLAGS \ ~(RQSFLAG_CONTINUATION|RQSFLAG_FULL|RQSFLAG_BADHEADER|RQSFLAG_BADPACKET) if (sp->req_header.rqs_flags & RQSFLAG_CONTINUATION) { IDPRINTF(3, ("%s: continuation segment\n", isp->isp_name)); ISP_WRITE(isp, INMAILBOX5, optr); continue; } if (sp->req_header.rqs_flags & RQSFLAG_FULL) { IDPRINTF(2, ("%s: internal queues full\n", isp->isp_name)); /* * We'll synthesize a QUEUE FULL message below. */ } if (sp->req_header.rqs_flags & RQSFLAG_BADHEADER) { PRINTF("%s: bad header\n", isp->isp_name); buddaboom++; } if (sp->req_header.rqs_flags & RQSFLAG_BADPACKET) { PRINTF("%s: bad request packet\n", isp->isp_name); buddaboom++; } if (sp->req_header.rqs_flags & _RQS_OFLAGS) { PRINTF("%s: unknown flags in response (0x%x)\n", isp->isp_name, sp->req_header.rqs_flags); buddaboom++; }#undef _RQS_OFLAGS } if (sp->req_handle > RQUEST_QUEUE_LEN || sp->req_handle < 1) { PRINTF("%s: bad request handle %d\n", isp->isp_name, sp->req_handle); ISP_WRITE(isp, INMAILBOX5, optr); continue; } xs = (void *) isp->isp_xflist[sp->req_handle - 1]; if (xs == NULL) { PRINTF("%s: NULL xs in xflist (handle %x)\n", isp->isp_name, sp->req_handle); isp_dumpxflist(isp); ISP_WRITE(isp, INMAILBOX5, optr); continue; } isp->isp_xflist[sp->req_handle - 1] = NULL; if (sp->req_status_flags & RQSTF_BUS_RESET) { isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); } if (buddaboom) { XS_SETERR(xs, HBA_BOTCH); } XS_STS(xs) = sp->req_scsi_status & 0xff; if (IS_SCSI(isp)) { if (sp->req_state_flags & RQSF_GOT_SENSE) { MEMCPY(XS_SNSP(xs), sp->req_sense_data, XS_SNSLEN(xs)); XS_SNS_IS_VALID(xs); } /* * A new synchronous rate was negotiated for this * target. Mark state such that we'll go look up * that which has changed later. */ if (sp->req_status_flags & RQSTF_NEGOTIATION) { sdparam *sdp = isp->isp_param; sdp += XS_CHANNEL(xs); sdp->isp_devparam[XS_TGT(xs)].dev_refresh = 1; isp->isp_update |= (1 << XS_CHANNEL(xs)); } } else { if (XS_STS(xs) == SCSI_CHECK) { XS_SNS_IS_VALID(xs); MEMCPY(XS_SNSP(xs), sp->req_sense_data, XS_SNSLEN(xs)); sp->req_state_flags |= RQSF_GOT_SENSE; } } if (XS_NOERR(xs) && XS_STS(xs) == SCSI_BUSY) { XS_SETERR(xs, HBA_TGTBSY); } if (sp->req_header.rqs_entry_type == RQSTYPE_RESPONSE) { if (XS_NOERR(xs)) { if (sp->req_completion_status != RQCS_COMPLETE) { isp_parse_status(isp, sp, xs); } else { XS_SETERR(xs, HBA_NOERROR); } } } else if (sp->req_header.rqs_entry_type == RQSTYPE_REQUEST) { if (sp->req_header.rqs_flags & RQSFLAG_FULL) { /* * Force Queue Full status. */ XS_STS(xs) = SCSI_QFULL; XS_SETERR(xs, HBA_NOERROR); } else if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BOTCH); } } else { PRINTF("%s: unhandled respose queue type 0x%x\n", isp->isp_name, sp->req_header.rqs_entry_type); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BOTCH); } } if (isp->isp_type & ISP_HA_SCSI) { XS_RESID(xs) = sp->req_resid; } else if (sp->req_scsi_status & RQCS_RU) { XS_RESID(xs) = sp->req_resid; IDPRINTF(4, ("%s: cnt %d rsd %d\n", isp->isp_name, XS_XFRLEN(xs), sp->req_resid)); } if (XS_XFRLEN(xs)) { ISP_DMAFREE(isp, xs, sp->req_handle - 1); } /* * XXX: If we have a check condition, but no Sense Data, * XXX: mark it as an error (ARQ failed). We need to * XXX: to do a more distinct job because there may * XXX: cases where ARQ is disabled. */ if (XS_STS(xs) == SCSI_CHECK && !(XS_IS_SNS_VALID(xs))) { if (XS_NOERR(xs)) { PRINTF("%s: ARQ failure for target %d lun %d\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs)); XS_SETERR(xs, HBA_ARQFAIL); } } if ((isp->isp_dblev >= 5) || (isp->isp_dblev > 2 && !XS_NOERR(xs))) { PRINTF("%s(%d.%d): FIN%d dl%d resid%d STS %x", isp->isp_name, XS_TGT(xs), XS_LUN(xs), sp->req_header.rqs_seqno, XS_XFRLEN(xs), XS_RESID(xs), XS_STS(xs)); if (sp->req_state_flags & RQSF_GOT_SENSE) { PRINTF(" Skey: %x", XS_SNSKEY(xs)); if (!(XS_IS_SNS_VALID(xs))) { PRINTF(" BUT NOT SET"); } } PRINTF(" XS_ERR=0x%x\n", (unsigned int) XS_ERR(xs)); } if (isp->isp_nactive > 0) isp->isp_nactive--; complist[ndone++] = xs; /* defer completion call until later */ } /* * If we looked at any commands, then it's valid to find out * what the outpointer is. It also is a trigger to update the * ISP's notion of what we've seen so far. */ if (nlooked) { ISP_WRITE(isp, INMAILBOX5, optr); isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4); } isp->isp_residx = optr; for (i = 0; i < ndone; i++) { xs = complist[i]; if (xs) { XS_CMD_DONE(xs); } } ENABLE_INTS(isp); return (1);}/* * Support routines. */static intisp_parse_async(isp, mbox) struct ispsoftc *isp; int mbox;{ u_int32_t fast_post_handle = 0; switch (mbox) { case MBOX_COMMAND_COMPLETE: /* sometimes these show up */ break; case ASYNC_BUS_RESET: { int bus; if (IS_1080(isp) || IS_12X0(isp)) { bus = ISP_READ(isp, OUTMAILBOX6); } else { bus = 0; } isp->isp_sendmarker = (1 << bus); isp_async(isp, ISPASYNC_BUS_RESET, &bus);#ifdef ISP_TARGET_MODE isp_notify_ack(isp, NULL);#endif break; } case ASYNC_SYSTEM_ERROR: mbox = ISP_READ(isp, OUTMAILBOX1); PRINTF("%s: Internal FW Error @ RISC Addr 0x%x\n", isp->isp_name, mbox); isp_restart(isp); /* no point continuing after this */ return (-1); case ASYNC_RQS_XFER_ERR: PRINTF("%s: Request Queue Transfer Error\n", isp->isp_name); break; case ASYNC_RSP_XFER_ERR: PRINTF("%s: Response Queue Transfer Error\n", isp->isp_name); break; case ASYNC_QWAKEUP: /* don't need to be chatty */ mbox = ISP_READ(isp, OUTMAILBOX4); break; case ASYNC_TIMEOUT_RESET: PRINTF("%s: timeout initiated SCSI bus reset\n", isp->isp_name); isp->isp_sendmarker = 1;#ifdef ISP_TARGET_MODE isp_notify_ack(isp, NULL);#endif break; case ASYNC_DEVICE_RESET: /* * XXX: WHICH BUS? */ isp->isp_sendmarker = 1; PRINTF("%s: device reset\n", isp->isp_name);#ifdef ISP_TARGET_MODE isp_notify_ack(isp, NULL);#endif break; case ASYNC_EXTMSG_UNDERRUN: PRINTF("%s: extended message underrun\n", isp->isp_name); break; case ASYNC_SCAM_INT: PRINTF("%s: SCAM interrupt\n", isp->isp_name); break; case ASYNC_HUNG_SCSI: PRINTF("%s: stalled SCSI Bus after DATA Overrun\n", isp->isp_name); /* XXX: Need to issue SCSI reset at this point */ break; case ASYNC_KILLED_BUS: PRINTF("%s: SCSI Bus reset after DATA Overrun\n", isp->isp_name); break; case ASYNC_BUS_TRANSIT: /* * XXX: WHICH BUS? */ mbox = ISP_READ(isp, OUTMAILBOX2); switch (mbox & 0x1c00) { case SXP_PINS_LVD_MODE: PRINTF("%s: Transition to LVD mode\n", isp->isp_name); ((sdparam *)isp->isp_param)->isp_diffmode = 0; ((sdparam *)isp->isp_param)->isp_ultramode = 0; ((sdparam *)isp->isp_param)->isp_lvdmode = 1; break; case SXP_PINS_HVD_MODE: PRINTF("%s: Transition to Differential mode\n", isp->isp_name); ((sdparam *)isp->isp_param)->isp_diffmode = 1; ((sdparam *)isp->isp_param)->isp_ultramode = 0; ((sdparam *)isp->isp_param)->isp_lvdmode = 0; break; case SXP_PINS_SE_MODE: PRINTF("%s: Transition to Single Ended mode\n", isp->isp_name); ((sdparam *)isp->isp_param)->isp_diffmode = 0; ((sdparam *)isp->isp_param)->isp_ultramode = 1; ((sdparam *)isp->isp_param)->isp_lvdmode = 0; break; default: PRINTF("%s: Transition to unknown mode 0x%x\n", isp->isp_name, mbox); break; } /* * XXX: Set up to renegotiate again! */ /* Can only be for a 1080... */ isp->isp_sendmarker = (1 << ISP_READ(isp, OUTMAILBOX6)); break; case ASYNC_CMD_CMPLT: fast_post_handle = (ISP_READ(isp, OUTMAILBOX2) << 16) | ISP_READ(isp, OUTMAILBOX1); IDPRINTF(3, ("%s: fast post completion of %u\n", isp->isp_name, fast_post_handle)); break; case ASYNC_CTIO_DONE: /* Should only occur when Fast Posting Set for 2100s */ PRINTF("%s: CTIO done\n", isp->isp_name); break; case ASYNC_LIP_OCCURRED: ((fcparam *) isp->isp_param)->isp_fwstate = FW_CONFIG_WAIT; isp->isp_sendmarker = 1; isp_mark_getpdb_all(isp); PRINTF("%s: LIP occurred\n", isp->isp_name); break; case ASYNC_LOOP_UP: ((fcparam *) isp->isp_param)->isp_fwstate = FW_CONFIG_WAIT; isp->isp_sendmarker = 1; isp_mark_getpdb_all(isp); isp_async(isp, ISPASYNC_LOOP_UP, NULL); break; case ASYNC_LOOP_DOWN:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -