⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_asc.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -