📄 scsi_asc.c
字号:
byteptr = (u_char *)sc->sc_rzaddr[targid]; break; /* end case INQUIRY */ case SZ_RDCAP: datacnt = SZ_RDCAP_LEN; break; /* end case READ CAPACITY */ case SZ_MODSNS: datacnt = (int) sc->sz_modsns.alclen; 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; } break; /* end case MODE SENSE */ case SZ_RECDIAG: case SZ_SNDDIAG: { if (sc->sc_devtyp[targid] & (SZ_DISK|SZ_CDROM)) { struct diagnostic_params *dp; dp = (struct diagnostic_params *) sc->sc_rzparams[targid]; datacnt = dp->dp_length; byteptr = (u_char *)sc->sc_rzaddr[targid]; } else { datacnt = SZ_RECDIAG_LEN; /* For tape driver. */ } break; /* end case RECEIVE DIAGNOSTICS */ } case SZ_REASSIGN: rp = (struct reassign_params *)sc->sc_rzparams[targid]; byteptr = (u_char *)sc->sc_rzparams[targid]; datacnt = ((rp->rp_header.defect_len0 << 0) & 0x00ff) + ((rp->rp_header.defect_len1 << 8) & 0xff00) + 4; break; /* end case REASSIGN BLOCK */ case SZ_FORMAT: dd = (struct defect_descriptors *)sc->sc_rzaddr[targid]; byteptr = (u_char *)sc->sc_rzaddr[targid]; datacnt = ((dd->dd_header.fu_hdr.defect_len0 << 0) & 0x00ff) + ((dd->dd_header.fu_hdr.defect_len1 << 8) & 0xff00) + 4; break; /* end case FORMAT */ case SZ_RDD: rdp = (struct read_defect_params *)sc->sc_rzparams[targid]; byteptr = (u_char *)sc->sc_rzaddr[targid]; datacnt = rdp->rdp_alclen; break; /* end case RDD */ case SZ_READL: case SZ_WRITEL: iox = (struct io_uxfer *)sc->sc_rzparams[targid]; byteptr = (u_char *)sc->sc_rzaddr[targid]; datacnt = iox->io_cnt; break; case SZ_READ_TOC: { register struct cd_toc *toc; toc = (struct cd_toc *)sc->sc_rzparams[targid]; datacnt = toc->toc_alloc_length; byteptr = (u_char *)sc->sc_rzaddr[targid]; break; } case SZ_READ_SUBCHAN: { register struct cd_sub_channel *sch; sch = (struct cd_sub_channel *)sc->sc_rzparams[targid]; datacnt = sch->sch_alloc_length; byteptr = (u_char *)sc->sc_rzaddr[targid]; break; } case SZ_READ_HEADER: { register struct cd_read_header *rh; rh = (struct cd_read_header *)sc->sc_rzparams[targid]; datacnt = rh->rh_alloc_length; byteptr = (u_char *)sc->sc_rzaddr[targid]; break; } case SZ_PLAYBACK_CONTROL: case SZ_PLAYBACK_STATUS: { register struct cd_playback *pb; pb = (struct cd_playback *)sc->sc_rzparams[targid]; datacnt = pb->pb_alloc_length; byteptr = (u_char *)sc->sc_rzaddr[targid]; break; } default: printf("asc_startdma: unknown scsi cmd 0x%x\n", sc->sz_opcode); return(SZ_RET_ABORT); break; } /* end switch(opcode) */ /* * Setup softc structure entries for special SCSI DISK * commands that do dma. (FORMAT UNIT), (READ DEFECT DATA), * (REASSIGN BLOCK), (MODE SELECT), (MODE SENSE) and * (INQUIRY). Q. Are these fields normally set by one of * the upper layers for reads and writes??? */ if (!(sc->sc_szflags[targid] & SZ_DMA_DISCON)) { PRINTD(targid, SCSID_DMA_FLOW, ("asc_startdma: !SZ_DMA_DISCON\n")); sc->sc_b_bcount[targid] = datacnt; sc->sc_bpcount[targid] = datacnt; sc->sc_bufp[targid] = (char *)byteptr; sc->sc_xfercnt[targid] = 0; } /* end if !DMA_DISCON */ else { PRINTD(targid, SCSID_DMA_FLOW, ("asc_startdma: ========> SZ_DMA_DISCON set <========\n")); } } /* end if opcode != READ/WRITE */SETUP_DMA: /* * Start of DMA code for a READ or WRITE scsi command, setup * the count, the RAM buffer offset, and the DMA registers. */ PRINTD(targid, SCSID_DMA_FLOW, ("asc_startdma: at SETUP_DMA: szflags = 0x%x \n", sc->sc_szflags[targid])); sc->sc_iodir[targid] = iodir; /* Setup the DMA subsystem for this target, and then start the DMA. The DMA subsystem is called for each amount of data to be transfered. Once the target has disconnected the DMA is considered "done". The value in sc_dmaxfer[] keeps track of the overall pieces of DMA. The value in sc_xfercnt[] is used to keep track of the "segments" that the user's request was broken into by the state machine. */ for (i=0; (*sc->dma_setup)( sc, targid, iodir, (sc->sc_bpcount[targid] - sc->sc_dmaxfer[targid]), (sc->sc_bufp[targid] + sc->sc_xfercnt[targid] + sc->sc_dmaxfer[targid])) == PDMA_RETRY && i<10000 ; i++ ) { } if (i > 9999 ) { cprintf( "asc_startdma: pdma_setup not returning PDMA_IDLE\n" ); } PRINTD(targid, 0x8000, ("asc_startdma: starting dma\n")); (*sc->dma_start)( sc, targid, DMA_CMD(ASC_XINFO) ); return(SZ_SUCCESS); } /* end asc_startdma */ /****************************************************************** * * Name: asc_sendcmd * * Abstract: Send the CDB to the target by loading from the * softc to the ASC FIFO and issuing the transfer * information command to the ASC. Note that this * case should only occur after a bus reset, when * we have to renegotiate the synchronous offset * with the drive. Under most cases, because of * the ASC's combination SELECT plus send CDB * command, this routine will not be called. * It possibly could occur if during the select * an error occurred which left the target selected * but without having transferred the CDB. The * interrupt would indicate phase COMMAND, and the * CDB would be loaded and transferred as indicated above. * * Inputs: * * sc - the softc data structure * * Outputs: None. * * Return values: None. * ******************************************************************/asc_sendcmd(sc, targid)register struct sz_softc *sc;int targid;{ int cntlr = sc->sc_ascnum; ASC_REG *ascaddr = ASC_REG_ADDR; /* setup the register pointer */ u_char *byteptr; int datacnt, i; int cmd_type; int cmdcnt; sc->sc_szflags[targid] = 0; sc->sc_savcnt[targid] = 0; sc->sc_ascdmacount[targid] = 0; byteptr = (u_char *)&sc->sz_command; cmd_type = *byteptr; cmdcnt = sz_cdb_length (cmd_type, targid); /* Put the scsi command onto the scsi bus */ asc_FIFOsenddata(sc, ASC_XINFO, byteptr, cmdcnt); /* Statistics update for READS and WRITES */ if ( (cmd_type == SZ_WRITE) || (cmd_type == SZ_READ) || (cmd_type == SZ_WRITE_10) || (cmd_type == SZ_READ_10) ) { if (sc->sc_dkn[targid] >= 0) { dk_busy |= 1 << sc->sc_dkn[targid]; dk_xfer[sc->sc_dkn[targid]]++; dk_wds[sc->sc_dkn[targid]] += sc->sc_bpcount[targid] >> 6; } /* end if dkn[targid] >= 0 */ } /* end if READ/WRITE */ return(SZ_SUCCESS);} /* end asc_sendcmd *//****************************************************************** * * Name: asc_getstatus * * Abstract: Read the status and message bytes from the FIFO by * issuing the Initiator Command Complete command. * Set the "combined cmd" state to ASC_CMD_CMPLT. * For normal command completion, the ASC will * generate a function complete interrupt, with BOTH * the status and message bytes in the FIFO and the * phase will be msg in. * * Inputs: * * sc - the softc data structure * io - boolean flag - if true, then call asc_recvdata, * else, status byte already in softc. * * Outputs: None. * * Return values: None. * ******************************************************************/asc_getstatus(sc, targid)register struct sz_softc *sc;int targid;{ int cntlr = sc->sc_ascnum; ASC_REG *ascaddr = ASC_REG_ADDR; /* setup the register pointer */ PRINTD(targid, (SCSID_CMD_EXP | SCSID_PHASE_STATE), ("asc_getstatus: status byte = 0x%x = ", sc->sc_status[targid])); PRINTD(targid, (SCSID_CMD_EXP | SCSID_PHASE_STATE), ("", asc_print_status((int)sc->sc_status[targid]))); /* To check the status a switch table is used to handle future, more complicated, status checking. */ /* Save the status byte for the error log */ if (sc->sc_curcmd[targid] == sc->sc_actcmd[targid]) sc->sc_statlog[targid] = sc->sc_status[targid]; switch(sc->sc_status[targid]) { /* All went well onto the next phase. Fall through to the return() */ case SZ_GOOD : break; /* Set the SZ_NEED_SENSE flag, the state mach. will handle the rest. */ /* Also, disable reselection until the RQSNS is completed. */ case SZ_CHKCND : sc->sc_szflags[targid] |= SZ_NEED_SENSE; break; /* Have to wait a bit for the target to be able to handle the request. Set the BUSYTARG flag to signal the interrupt handler of the BUSY condition. */ case SZ_BUSY : sc->sc_szflags[targid] |= SZ_BUSYTARG; /* set BUSY flag */ break; case SZ_INTRM : /* not handled for now */ case SZ_RESCNF : default: printf("asc_getstatus: target %d unexpected status = %x\n", targid, sc->sc_status[targid]); return(SZ_RET_ABORT); /* Assume bad failure for now */ break; } return(SZ_SUCCESS); /* every thing went well */} /* end asc_getstatus *//****************************************************************** * * name: asc_msgout * * abstract: Call the routine asc_sendata() to send the message * using DMA. Note that the send completion is * asynchronous! We should get an interrupt with * TC set in the status register and with BS set * in the interrupt status register. The phase * bits will indicate what action to take next. * * inputs: * * sc - the softc data structure * * outputs: none. * * return values: none. * ******************************************************************/asc_msgout(sc, targid)register struct sz_softc *sc;int targid;{ int cntlr = sc->sc_ascnum; ASC_REG *ascaddr = ASC_REG_ADDR; /* setup the register pointer */ u_long messg; int lun = sc->sz_t_read.lun; PRINTD(targid, SCSID_ENTER_EXIT, ("asc_msgout: enter, targid = %d\n", targid)); /* Check if we need to send a Message Reject Message */ if (asc_reject_message) { cprintf("asc_msgout: reject message TRUE\n"); asc_reject_message = 0; messg = SZ_MSGREJ; PRINTD(targid, SCSID_PHASE_STATE, ("asc_msgout: sending Message Reject Message\n")); /* Put the Message Reject Message onto the scsi bus */ asc_FIFOsenddata(sc, ASC_XINFO, &messg, 1); } /* end if reject_message */ /* Send the Identify Message with or without disconnects */ else { /* Clear the "asc_assert_attn" flag */ asc_assert_attn = 0; /* Check if we need to send a Synchronous DataXfer Message */ if (!sc->sc_ascsentsync[targid]) { sc->sc_ascsentsync[targid] = 1; PRINTD(targid, SCSID_PHASE_STATE, ("asc_msgout: sending Sync Data Transfer Message:\n")); /* Put the Synchronous Data Xfer Message onto the scsi bus */ sc->sc_extmessg[targid][0] = SZ_EXTMSG; sc->sc_extmessg[targid][1] = 0x3; sc->sc_extmessg[targid][2] = SZ_SYNC_XFER; sc->sc_extmessg[targid][3] = asc_sync_xfer_per; sc->sc_extmessg[targid][4] = sc->asc_sync_offset; asc_FIFOsenddata(sc, ASC_XINFO, &sc->sc_extmessg[targid][0], 5); } /* end if !sentsync */ else { /* Send a no-op just to get out of msgout phase. */ PRINTD(targid, SCSID_PHASE_STATE, ("asc_msgout: sending Noop Message\n")); messg = SZ_NOP; /* Put the Message Reject Message onto the scsi bus */ asc_FIFOsenddata(sc, ASC_XINFO, &messg, 1); } /* end else */ } /* end else */ return(SZ_SUCCESS);} /* end asc_msgout *//****************************************************************** * * name: asc_msgin * * abstract: If Function Complete bit set, read status and message * bytes from FIFO and call asc_getstatus to process the * status byte, else issue transfer Info command to * cause the target to send the message byte(s). * Process the message byte. * inputs: * * sc - the softc data structure * io - boolean flag - if TRUE, call asc_recvdata(), else * message byte already in softc structure. * * outputs: none. * * return values: none. * ******************************************************************/asc_msgin(sc, targid)register struct sz_softc *sc;int targid;{ int cntlr = sc->sc_ascnum; ASC_REG *ascaddr = ASC_REG_ADDR; /* setup the register pointer */ int len, i; int retval;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -