📄 scsi_asc.c
字号:
int save_xfercnt; int save_bpcount; int save_b_bcount; int save_resid; int save_dmaxfer;#if ASC_TEST_LOG if (!asc_tested_log) asc_test_log(sc, targid);#endif ASC_TEST_LOG /* * If "bp" is "0" we use polled scsi mode, disallow reselect * attempts, and disable interrupts for all transfers. We * poll for completion instead of allowing interrupts. */ PRINTD(targid, SCSID_ENTER_EXIT, ("\nasc_scsistart: STARTING cmd = 0x%x\n", sc->sz_opcode)); /* Fix for select/reselect problem */ if (!sc->scsi_bus_idle) { if ((sc->sc_devtyp[targid] & SZ_TAPE) && (sc->sc_curcmd[targid] == SZ_RQSNS)) { PRINTD(targid, 0x8000, ("asc_scsistart: bus !idle for RQSNS!\n")); } PRINTD(targid, SCSID_DISCONNECT, ("asc_scsistart: targ %x, bus not idle, returning BUSY\n", targid)); return(SZ_BUSBUSY); } /* end if !idle */ if (bp == (struct buf *)0) { sc->scsi_polled_mode = 1; } else { sc->scsi_polled_mode = 0; } /* Start a SCSI command on the passed target. */ sc->scsi_completed[targid] = 0; sc->scsi_bus_idle = 0; sc->sc_dmaxfer [targid] = 0; sc->sc_messgptr [targid] = &sc->sc_message [targid]; /* Check if we need to send a Synchronous DataXfer Message. At this time assume all commands will go via the manual process. Create a sel/cmd routine to do the select/ATN/CDB command. */ /* Perform target arbitration and selection */ if ((retval = asc_select_target(sc, targid)) != SZ_SUCCESS) {#ifdef ASC_LOGERR /* if bp == 0, this is probe(), and it is not an error to timeout then... */ if (bp != 0) { scsi_logerr(sc, 0, targid, SZ_ET_SELTIMO, 0, 0, SZ_HARDERR); }#else ASC_LOGERR printf("asc_scsistart: bad rtn code from select...0x%x\n", retval);#endif ASC_LOGERR return(retval); } /* end if asc_select_target != SUCCESS */ /* If in poll mode wait for an interrupt pending and then call the interrupt handler to take care of the rest. */ while (sc->scsi_polled_mode) { PRINTD(targid, SCSID_PHASE_STATE, ("asc_scsistart: COMMAND IN PROGRESS poll mode\n")); SZWAIT_UNTIL((ascaddr->asc_stat & ASC_INTP),asc_wait_count,retval); if (retval >= asc_wait_count) { int flags;#ifdef ASCDEBUG { int i; char *p; asc_show_regs(sc, sc->sc_ascnum, targid); p = (char*)&sc->sz_opcode; cprintf("cdb: "); for (i = 0; i < sz_cdb_length(sc->sz_opcode,targid); i++) { cprintf(" %x", *p++); } cprintf("\n"); }#endif ASCDEBUG#ifdef ASC_LOGERR scsi_logerr(sc, 0, targid, SZ_ET_BUSERR, 0x45, 0, flags);#else ASC_LOGERR printf("asc_scsistart: ASC_INTP not set in poll mode.\n");#endif ASC_LOGERR goto HANDLE_ABORT; } /* end if retval > asc_wait_count */ ascintr(cntlr); /* let the intr handle clean up */ PRINTD(targid, SCSID_ENTER_EXIT, ("asc_scsistart: flags after interrupt 0x%x\n", sc->sc_szflags[targid])); /* If the target is still working on the last command w/polling, go back and wait for the next interrupt to be serviced. */ if ( !sc->scsi_bus_idle ) { PRINTD( targid, SCSID_ENTER_EXIT, ("asc_scsistart: in poll, bus not idle loop again\n")); continue; } /* end if !scsi_bus_idle */ /* * Check the status of the SCSI operation. If the SCSI * operation completed with a good status return success, otherwise * indicate a problem. If a timeout occured during selection then * return abort. */ if (sc->sc_szflags[targid] & SZ_SELTIMEOUT) { return(SZ_RET_ABORT); } /* end if SELTIMEOUT */ if (sc->sc_status[targid] == SZ_GOOD) return(SZ_SUCCESS); else return(SZ_RET_ERR); } /* end while scsi_polled_mode */ /* Return the "inprogress status" allow the interrupt handler to take care of the rest of the command etal. */ return( SZ_IP );HANDLE_ABORT: /* Abort the current SCSI operation due to error */ PRINTD(targid, SCSID_ERRORS, ("asc_scsistart: command aborted (bus=asc%d target=%d cmd=0x%x)\n", cntlr, targid, sc->sc_curcmd[targid])); PRINTD(targid, SCSID_ERRORS, ("", asc_dumpregs(cntlr, WHO_ASC))); asc_reset(sc); sc->sc_selstat[targid] = SZ_IDLE; sc->sc_active = 0; return(SZ_RET_ABORT);} /* end asc_scsistart *//****************************************************************** * * Name: asc_select_target * * Abstract: Issue Select (With ATN) cmd to ASC after loading the * (ID byte and the) CDB into the ASC FIFO. The ASC will * arbitrate for the bus, send the contents of the FIFO to * the target, then generate an interrupt with the Function * Complete bit and Bus Service bits set, and with the * phase equal to Data In/Data Out. * * Note: we have to save the targid in sc_active here, * because there is no other way at interrupt time to * "remember" who we selected. * * TO DO: * * If necessary to send sync, issue Select w atn and stop command. * At the BS interrupt, (phase = msg out?) for each other msg byte, * issue Set ATN command, write byte to FIFO, and issue non-dma(?) * Xfer Info command.....????? * * Inputs: * * sc - the softc data structure * targid - the target id * * Outputs: None. * * Return values: None. * ******************************************************************/asc_select_target(sc, targid)register struct sz_softc *sc;int targid;{ int cntlr = sc->sc_ascnum; DMA_AR *ascar = ASC_AR_ADDR; ASC_REG *ascaddr = ASC_REG_ADDR; /* setup the register pointer */ int retval, i, ffr; u_long messg; int cmdcnt = 0; int lun = sc->sz_t_read.lun; char *cmdptr, *cmdout, cmdstr[20]; u_char command; /* * Begin the selection phase on the ASC chip with or without * disconnects. Setup the target Register and the * Command Register on the ASC to select a target on the SCSI * bus. */ sc->sc_ascdmacount[targid] = 0; cmdout = &cmdstr[0]; sc->sc_active = (1 << targid); /* See Note, above */ ascaddr->asc_dbid = targid; /* Set the dest. bus id */ wbflush(); /* Set Select/Reselect Timeout to maximum */ ascaddr->asc_srto = ASC_TIMEOUT; wbflush(); if (sc->scsi_polled_mode || sc->sc_no_disconnects[targid]) { cmdcnt = sz_cdb_length (sc->sz_opcode, targid); bcopy((char*)&(sc->sz_command), &cmdstr[0], cmdcnt); ascaddr->asc_so = sc->sc_ascreqack[targid]; wbflush(); ascaddr->asc_sp = sc->sc_ascsyncper[targid]; wbflush(); command = ASC_SELECT; /* 0x41 - No ATN! */ } /* end if polled_mode || no_disc */ else { messg = SZ_ID_DIS | lun; /* Allow disconnects */ PRINTD(targid, SCSID_ENTER_EXIT, ("asc_sel_tar: selecting target %d messg 0x%x, sentsync = %x\n", targid, messg, sc->sc_ascsentsync[targid])); /* If we haven't sent the sync message, send only 1 identify message byte to the target. This should generate a BS intr. with the phase = MESSAGE OUT. */ if (!(sc->sc_ascsentsync[targid])) { PRINTD(targid, (SCSID_DISCONNECT | SCSID_FLOW), ("asc_sel_tar: !sentsync, issuing SELATNSTOP cmd, msg = 0x%x\n", messg)); /* Write only a single message byte to FIFO (Identify) */ cmdstr[0] = messg; cmdcnt = 1; ascaddr->asc_so = sc->sc_ascreqack[targid]; wbflush(); ascaddr->asc_sp = sc->sc_ascsyncper[targid]; wbflush(); command = ASC_SELATNSTOP; /* 0x43 */ } /* end if !sentsync */ else { PRINTD(targid, SCSID_DISCONNECT, ("asc_sel_tar: syncper= 0x%x, reqack = 0x%x\n", sc->sc_ascsyncper[targid],sc->sc_ascreqack[targid])); /* Set up the sync. period and sync. offset registers */ ascaddr->asc_so = sc->sc_ascreqack[targid]; wbflush(); ascaddr->asc_sp = sc->sc_ascsyncper[targid]; wbflush(); cmdptr = (char*)&sc->sz_command; *cmdout++ = messg; cmdcnt++; for (i = 0; i < sz_cdb_length(sc->sz_opcode,targid); i++) { *cmdout++ = *cmdptr++; cmdcnt++; } /* end for */ command = ASC_SELATN; /* 0x42 */ } /* end else (sentsync == 1) */ } /* end else ! polled mode */ PRINTD(targid, SCSID_CMD_EXP, ("asc_sel_tar: ASC cmd: 0x%x, cmdcnt = 0x%x, CDB: ", (command | ASC_DMA), cmdcnt)); SZDEBUG_EXPAND(targid, &cmdstr[0], cmdcnt); PRINTD(targid, SCSID_CMD_EXP, ("\n")); /* Setup the FIFO for this target, and then start the transfer. */ asc_FIFOsenddata (sc, command, &cmdstr[0], cmdcnt); return(SZ_SUCCESS);} /* end asc_select_target *//****************************************************************** * * Name: asc_startdma * * Abstract: If a non-READ/WRITE command, set up the data count * for the command. Set up special softc fields (sort * of a pseudo-"bp") used by DMA routines. Either start * or restart the DMA transfer as appropriate. The ASC * will generate a Terminal Count zero interrupt if the * command completes normally. The Bus Service bit should * also be set in the ISR and the phase requested should * be Status, unless we get disconnected, which is a whole * other story to be told later.... * * Novelized Version: * * Various other variables and how they are used and set, both in this * routine and in restartdma and ascintr. * * byteptr (local) - initialized address for all non-read/write * commands to place their data. Points to sc->sz_dat[t]. HOWEVER, * if rzspecial[t], then set to point to sc->sc_rzparams[t]. * * datacnt - initialized on a per-command basis for the expected length * of the transfer. * * * * Inputs: * * sc - the softc data structure * iodir - the direction of the DMA transfer * * Outputs: None. * * Return values: None. * ******************************************************************/asc_startdma(sc, iodir, targid)register struct sz_softc *sc;int iodir;int targid;{ int cntlr = sc->sc_ascnum; ASC_REG *ascaddr = ASC_REG_ADDR; /* setup the register pointer */ u_char *byteptr; char *bufp; int datacnt, i; int retval, offset; int dmacount; struct format_params *fp; struct reassign_params *rp; struct read_defect_params *rdp; struct defect_descriptors *dd; struct mode_sel_sns_params *msp; struct io_uxfer *iox; PRINTD(targid, SCSID_ENTER_EXIT, ("asc_startdma: enter, iodir = 0x%x\n", iodir)); /* * Handle non READ/WRITE scsi commands that transfer data. */ if ( (sc->sz_opcode == SZ_WRITE) || (sc->sz_opcode == SZ_READ) || (sc->sz_opcode == SZ_WRITE_10) || (sc->sz_opcode == SZ_READ_10) ) { PRINTD(targid, SCSID_DMA_FLOW, ("asc_startdma: READ/WRITE COMMAND STARTING ****************\n")); } /* end if READ || WRITE */ if ( (sc->sz_opcode != SZ_WRITE) && (sc->sz_opcode != SZ_READ) && (sc->sz_opcode != SZ_WRITE_10) && (sc->sz_opcode != SZ_READ_10) ) { byteptr = (u_char *)&sc->sz_dat[targid]; switch(sc->sz_opcode) { case SZ_MODSEL: byteptr = (u_char *)&sc->sc_dat[0]; datacnt = (int) sc->sz_modsel.pll; if(sc->sc_rzspecial[targid]) { msp = (struct mode_sel_sns_params *)sc->sc_rzparams[targid]; byteptr = (u_char *)sc->sc_rzaddr[targid]; datacnt = msp->msp_length; } PRINTD(targid, SCSID_CMD_EXP, ("\n\nasc_startdma: MODE SELECT data:")); SZDEBUG_EXPAND(targid, byteptr, datacnt); PRINTD(targid, SCSID_CMD_EXP, ("\n")); break; /* end case MODE_SELECT */ case SZ_RQSNS: byteptr = (u_char *)&sc->sc_sns[targid]; datacnt = sc->sz_rqsns.alclen; break; /* end case REQUEST SENSE */ case SZ_INQ: datacnt = SZ_INQ_MAXLEN; if(sc->sc_rzspecial[targid])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -