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

📄 scsi_disk.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
		/*		 * Copy in the write long data from user space.		 */		if(copyin( iox->io_addr, sc->sc_rzaddr[targid],				iox->io_cnt) != 0){		    reterr = EFAULT;		    break;		}		if ((reterr = rzcommand (dev, SZ_WRITEL, 1, 0)) == EINTR) {			break;		}		if(sc->sc_c_status[targid] != SZ_GOOD) {		    mprintf("rzspecial: %s unit %d: write lond data failed\n",		    sc->sc_device[targid], unit);		    reterr = EIO;		    break;	        }		break;		case SCSI_READ_LONG:		iox = (struct io_uxfer *)data;		if( iox->io_cnt > sizeof(*dd) ){		    reterr = EINVAL;		    break;		}		bcopy(data, sc->sc_rzparams[targid], sizeof(*iox));		if ((reterr = rzcommand (dev, SZ_READL, 1, 0)) == EINTR) {			break;		}		if(sc->sc_c_status[targid] != SZ_GOOD) {		    mprintf("rzspecial: %s unit %d: read lond data failed\n",		    sc->sc_device[targid], unit);		    reterr = EIO;		    break;	        }		/*		 * Copy out the read long data to user space.		 */		if(copyout(sc->sc_rzaddr[targid], iox->io_addr, 				iox->io_cnt) != 0)		    reterr = EFAULT;		break;		case SCSI_VERIFY_DATA:		bcopy(data, sc->sc_rzparams[targid], sizeof(*vp));		if ((reterr = rzcommand (dev, SZ_VFY_DATA, 1, 0)) == EINTR) {			break;		}		if(sc->sc_c_status[targid] != SZ_GOOD) {		    mprintf("rzspecial: %s unit %d: verify data failed\n",		    sc->sc_device[targid], unit);		    reterr = EIO;	        }		break;		case SCSI_MODE_SENSE:		if ((reterr = rzcommand (dev, SZ_MODSNS, 1, 0)) == EINTR) {			break;		}		if(sc->sc_c_status[targid] != SZ_GOOD) {		    mprintf("rzspecial: %s unit %d: mode sense failed\n",		    sc->sc_device[targid], unit);		    reterr = EIO;		    break;	        }		/*		 * Copy out the mode sense data to user space.		 */		if(copyout(sc->sc_rzaddr[targid], msp->msp_addr, 				msp->msp_length) != 0)		    reterr = EFAULT;		break;		case SCSI_MODE_SELECT:		/*		 * Must be super user to CHANGE the disk parameters.		 */		if (!suser()) {		    	reterr = EACCES;			break;		}		/*		 * Copy in the mode select data from user space.		 */		if(copyin(msp->msp_addr, sc->sc_rzaddr[targid],				msp->msp_length) != 0) {			reterr = EFAULT;			break;		}		if ((reterr = rzcommand (dev, SZ_MODSEL, 1, 0)) == EINTR) {			break;		}		if(sc->sc_c_status[targid] != SZ_GOOD) {		    mprintf("rzspecial: %s unit %d: mode select failed\n",		    sc->sc_device[targid], unit);		    reterr = EIO;	        }		break;	case SCSI_GET_SENSE:		es = (struct extended_sense *)data;		bcopy((char *)&sc->sc_rzsns[targid], data, sizeof(*es));		bzero((char *)&sc->sc_rzsns[targid], 				sizeof(sc->sc_rzsns[targid]));		break;	case SCSI_GET_INQUIRY_DATA:		if ((reterr = rzcommand (dev, SZ_INQ, 1, 0)) == EINTR) {			break;		}		if(sc->sc_c_status[targid] != SZ_GOOD) {		    mprintf("rzspecial: %s unit %d: inquiry failed\n",		    sc->sc_device[targid], unit);		    reterr = EIO;		    break;	        }		if(copyout(sc->sc_rzaddr[targid], msp->msp_addr, 				msp->msp_length) != 0)		    reterr = EFAULT;		break;		default:		reterr = ENXIO;		break;	}	sc->sc_rzspecial[targid] = 0;	KM_FREE(sc->sc_rzaddr[targid], KM_DEVBUF);	return(reterr);}rzdump(){}/* * * Name:		rz_bbr		-Disk bad block replacement routine * * Abstract:		This routine is called from the disk completion routine *			to perform BBR on LBN contained in the sense info. *			The LBN is read, reassigned, and written back.  The  *			original request is repeated and it's status returned *			to the user. * Inputs: * * sc			Pointer to controller's sz_softc structure. * targid		Device SCSI target ID (0 - 7). * cbp			Buffer pointer of the current command. * * Outputs:		Error messages depending on the success/fail of the BBR *			progress. * * Return Values: 	A flag back to the completion routine signaling what *			to do with the existing buffer on the front of the *			queue. * * Side Effects: 	The buffer queue is changed to insert or remove the *			bbr buffer on the front.  The state machine is entered *			many times.  However the current operation is repeated *			to get the necessary information back to the user. *			The macros KM_ALLOC/KM_FREE are called. * * To Do:		Make the BBR SM multipass, w/single pass it is a little *			ugly.  Work out a good handshake with rzdisk.  If rzdisk *			goes to replace a ECC block, this routine will do it *			before the read data gets back to rzdisk.  Workup a way *			to turnoff error logging ? */rz_bbr( sc, targid, cbp )    register struct sz_softc *sc;    register int targid;    struct buf *cbp;			/* bp for current operation */{    register struct buf *dp;    register struct buf *bp;    struct reassign_params *rp;    int unit;    int release;    int flags;    char *p;		/* general purpose byte pointers */    char *q;    int i;    unit = minor(cbp->b_dev) >> 3;    dp = &szutab[ unit ];    bp = &bszbuf[ targid ];    release = 1;		/* Default: release front buffer */  /* Check to see if DBBR is disabled for this device.  If the SCSI_NODBBR    flag is set return to the completion routine. */    if( ((sc->sc_devtab[targid])->flags & SCSI_NODBBR ) != 0)	return( release );  /* Check the active flag, is the target already in BBR state. */    if( !( sc->sc_bbr_active[ targid ] == 1 ))    {      /* Check out the additional sence codes.  BBR will be done on ECC level	errors.  Read retry errors for now will be ignored. */	if( sc->sc_sns[targid].asb.rz_asb.asc == SZ_ASC_RRETRY )	{	  /* On a read retry, simply leave and allow the current buffer to 	    complete. */	    PRINTD( targid, 0x200, ("BBR Recovered error a read retry\n"));	    return( 1 );	/* free up the buffer */	  /* FUTURE: save LBN for compare on next RRETRY */	}	else if( sc->sc_sns[targid].asb.rz_asb.asc != SZ_ASC_RERROR )	{	  /* On a unhandled error code, simply leave and allow the current	    buffer to complete. */	    PRINTD( targid, 0x200, ("BBR Recovered error not a read ECC\n"));	    return( 1 );	/* free up the buffer */	}      /* On an error with ECC correction, go through the BBR process. */      /* Allocate a working data buffer for the read data. Two 512 chuncks	are allocated one is for the read/write data the other is for the	reassign data block containing the bad block info. *//* JAG remove magic ##'s and use defines */	KM_ALLOC( sc->sc_bbraddr[targid], char *, 			1024, KM_DEVBUF, (KM_NOWAIT|KM_CLEAR) );	if(sc->sc_bbraddr[targid] == NULL)	{	    mprintf("rz_bbr: Unable to alloc working buffer for DBBR\n" );	    return( 1 );	/* free up the buffer */	}	sc->sc_bbrparams[targid] = sc->sc_bbraddr[targid] + 512;      /* Load the bp etal with what ever is needed.  Then let the SCSI State        Machine handle the work.  The BBR states will handle "what just 	happened". */	bp->b_flags = (B_BUSY | B_READ );	/* read into ker mem */	bp->b_un.b_addr = sc->sc_bbraddr[ targid ];	/* where to read */	bp->b_bcount = 512;				/* MAGIC # one block */	bp->b_retry = 0;				/* no retry in SM */	bp->b_resid = 0;      /* Setup the block # and dev entry for the bad block.  The block is kept	in the info bytes of the sence data.  The block is "absolute" from the	drives point of view.  The b_dev entry has to be modified to fake the	state machine out to use C partition */	bp->b_dev = (((cbp->b_dev) & ~(7)) | 2 );	/* C is #2 */	bp->b_blkno = sz_sbtol( &(sc->sc_sns[targid].infobyte3) ); /* LBN # */      /* Pre-load the reassign parameter part of the data block.  Only the one	block will be reassigned.  This information will be use in the 	reassign part of the SM. */	rp = (struct reassign_params *)sc->sc_bbrparams[ targid ];	rp->rp_header.defect_len1 = 0;	rp->rp_header.defect_len0 = 4;		/* only 1 LBN = 4 bytes */	p = (char *)&(rp->rp_header.defect_len0);	p++;				/* inc to the defect desc section */	q = (char *)&(sc->sc_sns[ targid ].infobyte3); 	/* LBN # */	for( i = 0; i < 4; i++ )	/* xfer the bytes from sns to rp */	{	    *p++ = *q++;	}      /* Set the BBR active flag, and place the buffer onto the front of the	queue.  This will leave the bp that "failed" still on the queue and	next in line.  When the BBR has completed, this bp can be acted upon.      ASSUMPTION: Playing with the queue.  The priority level should still	be high enough to block. */	sc->sc_bbr_active[ targid ] = 1;	/* now ready to work */	bp->b_actf = dp->b_actf;	/* copy forward link */	dp->b_actf = bp;		/* add to the front of the queue */	sc->sc_bbr_state[targid] = BBR_READ;	sc->sc_bbr_read[targid] = BBR_COUNT;	/* counts decrement */	sc->sc_bbr_oper[targid] = SZ_RW_START;	/* signal a normal cmd */	sz_retries[unit] = SZ_RW_RTCNT;		/* preset cnt for no retries */      /* Setup the state for the SM and clear active.  The SM will scan the	queue and find the next available entry to startup. */	sc->sc_xstate[targid] = SZ_NEXT;	sc->sc_xevent[targid] = SZ_BEGIN;	dp->b_active = 0;		/* no longer an active queue */    }    else    {      /* The target is in BBR state.  Using the bbr state variables in the sc	structure work on what is needed.  */	PRINTD( targid, 0x200, ("BBR state: %d\n", sc->sc_bbr_state[targid]));	switch( sc->sc_bbr_state[ targid ] )	{	    case BBR_READ :	      /* Check the sence key(s) has the block gone from bad to good		or worse ? */		if( sc->sc_sns[targid].snskey == SZ_NOSENSE )		{		  /* Stop BBR things appear to be back to normal. */		    sc->sc_bbr_active[ targid ] = 0;	/* all done */		    break;		}		if( sc->sc_sns[targid].snskey == SZ_MEDIUMERR )		{		  /* The block has completly gone bad.  Stop any BBR, report		    the error, logging was disabled in the SM during BBR. */		    flags = SZ_HARDERR;		    scsi_logerr(sc, bp, targid, SZ_ET_DBBR, 0, 0, flags);		    sc->sc_bbr_active[ targid ] = 0;	/* all done */		    break;		}	      /* Check the read counts for BBR_READ.  If the count is not 0		try the read again. */		if( --sc->sc_bbr_read[targid] != 0 )		{		  /* Restart the current bp at the front of the queue. */		    bp->b_flags = (B_BUSY | B_READ );	/* reload */		    bp->b_bcount = 512;				/* MAGIC # */		}		else		{		  /* Setup the BBR related stuff.  The parameter and defect 		    information has already been setup. */		    sc->sc_bbr_state[targid] = BBR_REASSIGN;		    sc->sc_bbr_rawr[targid] = BBR_COUNT;	/* counts dec */		    sc->sc_bbr_oper[targid] = SZ_SP_START;	/* special */		    sz_retries[unit] = SZ_SP_RTCNT;	/* preset: no retries */		  /* Setup the buffer to contain the information needed for		    the reassign. */		    bp->b_comand = SZ_REASSIGN;		  /* Use the rzspecial flag to fake out the SM and have it		    use some of the logic for reassign. */		    sc->sc_rzspecial[ targid ] = 1;		    sc->sc_rzparams[ targid ] = sc->sc_bbrparams[ targid ];		}	    break;	    case BBR_REASSIGN :	      /* Clear the rzspecial flag it is used only during the Reassign		and should not be around. */		sc->sc_rzspecial[ targid ] = 0;	      /* Was the reassign successfull?  If not fail with an error		message.  Else go an try the write. */		if( sc->sc_sns[targid].snskey != SZ_NOSENSE ) 		{		    flags = SZ_HARDERR;		    scsi_logerr(sc, bp, targid, SZ_ET_DBBR, 1, 0, flags);		    sc->sc_bbr_active[ targid ] = 0;	/* error out */		}		else		{		  /* Setup for the write of the buffered data. */		    sc->sc_bbr_state[targid] = BBR_WRITE;		    sc->sc_bbr_write[targid] = BBR_COUNT;	/* counts dec */		    sc->sc_bbr_oper[targid] = SZ_RW_START;	/* normal cmd */		    sz_retries[unit] = SZ_RW_RTCNT;	/* preset: 0 retries */		    bp->b_flags = ( B_BUSY );	/* write from ker mem */		    bp->b_bcount = 512;			/* MAGIC # one block */		    bp->b_retry = 0;			/* no retry in SM */		    bp->b_resid = 0;		}	    break;	    case BBR_WRITE :	      /* Check the sence key(s) has the block successufully been		written to the disk ?. */		if( sc->sc_sns[targid].snskey == SZ_NOSENSE )		{		  /* Stop BBR the write has completed.  The previous buffer		    on the queue will be re-tried to allow the command to		    retry. */		    flags = SZ_SOFTERR;		    scsi_logerr(sc, bp, targid, SZ_ET_DBBR, 2, 0, flags);		    sc->sc_bbr_active[ targid ] = 0;	/* all done */		    release = 0;			/* repeat the command */		    break;		}	      /* Check the write counts for BBR_WRITE.  If the count is not 0		try the write again.  If the write counts have reached zero		try to reassign the block again. */		if( --sc->sc_bbr_write[targid] != 0 )		{		  /* Restart the current bp at the front of the queue. */		    bp->b_flags = ( B_BUSY );		/* reload */		    bp->b_bcount = 512;				/* MAGIC # */		}		else		{		  /* Check the reassign/write count.  Reset the BBR state to		    reassign and try again.  If the reassign/write counts		    have also reached zero, stop BBR and report the failure. */		    if( --sc->sc_bbr_rawr[targid] != 0 )		    {		      /* Setup the BBR related stuff.  The parameter and defect 			information has already been setup. */			sc->sc_bbr_state[targid] = BBR_REASSIGN;			sc->sc_bbr_oper[targid] = SZ_SP_START; /* special cmd */			sz_retries[unit] = SZ_SP_RTCNT;	/* preset for 0 retry */		      /* Setup the buffer to contain the information needed for			the reassign. */			bp->b_comand = SZ_REASSIGN;		      /* Use the rzspecial flag to fake out the SM and have it			use some of the logic for reassign. */			sc->sc_rzspecial[ targid ] = 1;			sc->sc_rzparams[ targid ] = sc->sc_bbrparams[ targid ];		    }		    else	/* reassign-write count == 0 */		    {		      /* The BBR has failed, report the error and terminate			the BBR state. */			flags = SZ_HARDERR;			scsi_logerr(sc, bp, targid, SZ_ET_DBBR, 3, 0, flags);			sc->sc_bbr_active[targid] = 0;	/* stop */		    }		}	    break;	    default:		 /* something is wrong release the buffer */		sc->sc_bbr_active[ targid ] = 0;	    break;	}    }  /* Check out the BBR active flag.  If the target is still in BBR mode    leave the routine.  If BBR is done free up the allocated memory and    remove the BBR bp and allow the front buffer to be dequeued.  If active    is set setup the state for the SM. */    if( sc->sc_bbr_active[ targid ] == 0 )    {	PRINTD( targid, 0x200, ("BBR done: cleaning up\n"));	KM_FREE(sc->sc_bbraddr[targid], KM_DEVBUF);	sc->sc_bbr_oper[targid] = 0;	/* clear the opcode */	bp = dp->b_actf;		/* pop off BBR buffer */	dp->b_actf = bp->b_actf;    }    else    {      /* Set the release flag to "no", the state for the command will be setup	so that the SM will scan the queue and find the next available entry	to startup.  The snskey is pre-cleared, it is not cleared with in the	SM. */	PRINTD( targid, 0x200, ("BBR active setup for SM\n"));	sc->sc_sns[targid].snskey = SZ_NOSENSE;		/* to make sure */	release = 0;			/* do not remove front buffer */    }  /* Return what the completion code needes to do with the existing buffer    on the front of the queue. */    if( release == 0 )    {      /* Setup the state for the SM and clear b_active.  The SM will scan the	queue and find the next available entry to startup.  The snskey is	pre-cleared, it is not cleared with in the SM. */	sc->sc_xstate[targid] = SZ_NEXT;	sc->sc_xevent[targid] = SZ_BEGIN;	dp->b_active = 0;		/* no longer an active queue */    }    return( release );}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -