From owner-freebsd-hackers Sat Mar 25 01:34:25 1995 Return-Path: hackers-owner Received: (from majordom@localhost) by freefall.cdrom.com (8.6.10/8.6.6) id BAA14889 for hackers-outgoing; Sat, 25 Mar 1995 01:34:25 -0800 Received: from tfs.com (mailhub.tfs.com [140.145.250.1]) by freefall.cdrom.com (8.6.10/8.6.6) with SMTP id BAA14882 for ; Sat, 25 Mar 1995 01:34:23 -0800 Received: by tfs.com (smail3.1.28.1) Message-Id: Date: Sat, 25 Mar 95 01:33 PST From: julian@tfs.com (Julian Elischer) To: hackers@FreeBSD.org Subject: OOPS previous patch flawed Sender: hackers-owner@FreeBSD.org Precedence: bulk NATURALLY I spotted a flaw in the patch just AFTER I posted it.. here is the fixed version.. ###############cut here############ *** 1.4 1995/03/25 01:22:38 --- st.c 1995/03/25 09:17:10 *************** *** 1859,1870 **** flags)); } - #ifdef NETBSD - #define SIGNAL_SHORT_READ - #else - #define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR; - #endif - /* * Look at the returned sense and act on the error and detirmine * The unix error number to pass back... (0 = report no error) --- 1859,1864 ---- *************** *** 1889,1981 **** if (sense->error_code & SSD_ERRCODE_VALID) { info = ntohl(*((int32 *) sense->ext.extended.info)); } else { ! info = xs->datalen; /* bad choice if fixed blocks */ } if ((sense->error_code & SSD_ERRCODE) != 0x70) { ! return SCSIRET_CONTINUE; /* let the generic code handle it */ } ! if (st->flags & ST_FIXEDBLOCKS) { ! xs->resid = info * st->blksiz; ! if (sense->ext.extended.flags & SSD_EOM) { ! st->flags |= ST_EIO_PENDING; ! if (bp) { ! bp->b_resid = xs->resid; ! SIGNAL_SHORT_READ ! } ! } ! if (sense->ext.extended.flags & SSD_FILEMARK) { ! st->flags |= ST_AT_FILEMARK; ! if (bp) { ! bp->b_resid = xs->resid; ! SIGNAL_SHORT_READ } - } - if (sense->ext.extended.flags & SSD_ILI) { - st->flags |= ST_EIO_PENDING; - if (bp) { - bp->b_resid = xs->resid; - SIGNAL_SHORT_READ - } - if (sense->error_code & SSD_ERRCODE_VALID && - !silent) - printf("st%d: block wrong size" - ", %d blocks residual\n", unit - ,info); - /* ! * This quirk code helps the drive read ! * the first tape block, regardless of ! * format. That is required for these ! * drives to return proper MODE SENSE ! * information. */ ! if ((st->quirks & ST_Q_SNS_HLP) && ! !(sc_link->flags & SDEV_MEDIA_LOADED)) { ! st->blksiz -= 512; ! } ! } ! /* ! * If no data was tranfered, do it immediatly ! */ ! if (xs->resid >= xs->datalen) { ! if (st->flags & ST_EIO_PENDING) { ! return EIO; ! } ! if (st->flags & ST_AT_FILEMARK) { ! if (bp) { ! bp->b_resid = xs->resid; ! SIGNAL_SHORT_READ } - return 0; } - } - } else { /* must be variable mode */ - xs->resid = xs->datalen; /* to be sure */ - if (sense->ext.extended.flags & SSD_EOM) { - return (EIO); - } - if (sense->ext.extended.flags & SSD_FILEMARK) { - if (bp) - bp->b_resid = bp->b_bcount; return 0; ! } ! if (sense->ext.extended.flags & SSD_ILI) { ! if (info < 0) { ! /* ! * the record was bigger than the read ! */ ! if (!silent) ! printf("st%d: %d-byte record " ! "too big\n", unit, ! xs->datalen - info); return (EIO); } ! xs->resid = info; ! if (bp) { ! bp->b_resid = info; ! SIGNAL_SHORT_READ } } } key = sense->ext.extended.flags & SSD_KEY; --- 1883,1969 ---- if (sense->error_code & SSD_ERRCODE_VALID) { info = ntohl(*((int32 *) sense->ext.extended.info)); } else { ! if (st->flags & ST_FIXEDBLOCKS) { ! info = xs->datalen / st->blksiz; ! } else { ! info = xs->datalen; ! } } if ((sense->error_code & SSD_ERRCODE) != 0x70) { ! return SCSIRET_CONTINUE;/* let the generic code handle it */ } ! if(st->flags & (SSD_EOM|SSD_FILEMARK|SSD_ILI)) { ! if (st->flags & ST_FIXEDBLOCKS) { ! xs->resid = info * st->blksiz; ! xs->flags |= SCSI_RESID_VALID; ! if (sense->ext.extended.flags & SSD_EOM) { ! st->flags |= ST_EIO_PENDING; ! } ! if (sense->ext.extended.flags & SSD_FILEMARK) { ! st->flags |= ST_AT_FILEMARK; ! } ! if (sense->ext.extended.flags & SSD_ILI) { ! st->flags |= ST_EIO_PENDING; ! if (sense->error_code & SSD_ERRCODE_VALID && ! !silent) ! printf("st%d: block wrong size" ! ", %d blocks residual\n", unit ! ,info); ! /*XXX*/ /* is this how it works ? */ ! /* check def of ILI for fixed blk tapes */ ! ! /* ! * This quirk code helps the drive read ! * the first tape block, regardless of ! * format. That is required for these ! * drives to return proper MODE SENSE ! * information. ! */ ! if ((st->quirks & ST_Q_SNS_HLP) && ! !(sc_link->flags & SDEV_MEDIA_LOADED)) { ! st->blksiz -= 512; ! } } /* ! * If no data was tranfered, do it immediatly */ ! if (xs->resid >= xs->datalen) { ! xs->flags &= ~SCSI_RESID_VALID; ! if (st->flags & ST_AT_FILEMARK) { ! xs->flags |= SCSI_EOF; ! st->flags &= ~ST_AT_FILEMARK; ! return 0; ! } ! if (st->flags & ST_EIO_PENDING) { ! st->flags &= ~ST_EIO_PENDING; ! return EIO; } } return 0; ! } else { /* must be variable mode */ ! xs->resid = xs->datalen; /* to be sure */ ! if (sense->ext.extended.flags & SSD_EOM) { return (EIO); } ! if (sense->ext.extended.flags & SSD_FILEMARK) { ! xs->flags |= SCSI_EOF; ! } ! if (sense->ext.extended.flags & SSD_ILI) { ! if (info < 0) { ! /* ! * the record was bigger than the read ! */ ! if (!silent) ! printf("st%d: %d-byte record " ! "too big\n", unit, ! xs->datalen - info); ! return (EIO); ! } ! xs->resid = info; ! xs->flags |= SCSI_RESID_VALID; } } + return 0; } key = sense->ext.extended.flags & SSD_KEY; *************** *** 1987,2005 **** * MODE SENSE information. */ if ((st->quirks & ST_Q_SNS_HLP) && ! !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */ st->blksiz -= 512; } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { st->flags |= ST_BLANK_READ; ! xs->resid = xs->datalen; ! if (bp) { ! bp->b_resid = xs->resid; ! /*return an EOF */ ! } return (ESUCCESS); } } ! return SCSIRET_CONTINUE; /* let the default/generic handler handle it */ } /* --- 1975,1990 ---- * MODE SENSE information. */ if ((st->quirks & ST_Q_SNS_HLP) && ! !(sc_link->flags & SDEV_MEDIA_LOADED)) { ! /* still starting */ st->blksiz -= 512; } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) { st->flags |= ST_BLANK_READ; ! xs->flags |= SCSI_EOF; return (ESUCCESS); } } ! return SCSIRET_CONTINUE; /* Use the the generic handler */ } /* *** 1.4 1995/03/25 01:22:38 --- scsi_base.c 1995/03/25 09:28:48 *************** *** 17,22 **** --- 17,23 ---- #include #include #include + #include #include #include #include *************** *** 61,66 **** --- 62,68 ---- sc_link->flags |= SDEV_WAITING; tsleep((caddr_t)sc_link, PRIBIO, "scsiget", 0); } + sc_link->active++; sc_link->opennings--; if (xs = next_free_xs) { next_free_xs = xs->next; *************** *** 97,102 **** --- 99,105 ---- SC_DEBUG(sc_link, SDEV_DB3, ("free_xs\n")); /* if was 0 and someone waits, wake them up */ + sc_link->active--; if ((!sc_link->opennings++) && (sc_link->flags & SDEV_WAITING)) { sc_link->flags &= ~SDEV_WAITING; wakeup((caddr_t)sc_link); /* remember, it wakes them ALL up */ *************** *** 356,361 **** --- 359,367 ---- } /* BUG: This isn't used anywhere. Do you have plans for it, * Julian? (dufault@hda.com). + * This allows a private 'done' handler to + * resubmit the command if it wants to retry, + * In this case the xs must NOT be freed. (julian) */ if (retval == -2) { return; /* it did it all, finish up */ *************** *** 427,433 **** if (bp && !(flags & SCSI_USER)) flags |= SCSI_NOSLEEP; SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); ! xs = get_xs(sc_link, flags); /* should wait unless booting */ if (!xs) return (ENOMEM); /* * Fill out the scsi_xfer structure. We don't know whose context --- 433,439 ---- if (bp && !(flags & SCSI_USER)) flags |= SCSI_NOSLEEP; SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); ! xs = get_xs(sc_link, flags); if (!xs) return (ENOMEM); /* * Fill out the scsi_xfer structure. We don't know whose context *************** *** 442,448 **** xs->cmdlen = cmdlen; xs->data = data_addr; xs->datalen = datalen; ! xs->resid = datalen; xs->bp = bp; /*XXX*/ /*use constant not magic number */ if (datalen && ((caddr_t) data_addr < (caddr_t) KERNBASE)) { --- 448,454 ---- xs->cmdlen = cmdlen; xs->data = data_addr; xs->datalen = datalen; ! xs->resid = datalen; /* just to be safe, but don't mark as VALID */ xs->bp = bp; /*XXX*/ /*use constant not magic number */ if (datalen && ((caddr_t) data_addr < (caddr_t) KERNBASE)) { *************** *** 503,510 **** switch (retval) { case SUCCESSFULLY_QUEUED: ! if (bp) ! return retval; /* will sleep (or not) elsewhere */ s = splbio(); while (!(xs->flags & ITSDONE)) { tsleep((caddr_t)xs, PRIBIO + 1, "scsicmd", 0); --- 509,517 ---- switch (retval) { case SUCCESSFULLY_QUEUED: ! if (bp) { ! return 0; /* will sleep (or not) elsewhere */ ! } s = splbio(); while (!(xs->flags & ITSDONE)) { tsleep((caddr_t)xs, PRIBIO + 1, "scsicmd", 0); *************** *** 561,566 **** --- 568,616 ---- return (retval); } + /* + * submit a scsi command, given the command.. used for retries + * and callable from timeout() + */ + #ifdef NOTYET + errval scsi_submit(xs) + struct scsi_xfer *xs; + { + struct scsi_link *sc_link = xs->sc_link; + int retval; + + retval = (*(sc_link->adapter->scsi_cmd)) (xs); + + return retval; + } + + /* + * Retry a scsi command, given the command, and a delay. + */ + errval scsi_retry(xs,delay) + struct scsi_xfer *xs; + int delay; + { + if(delay) + { + timeout(((void())*)scsi_submit,xs,hz*delay); + return(0); + } + else + { + return(scsi_submit(xs)); + } + } + #endif + + /* + * handle checking for errors.. + * called at interrupt time from scsi_done() and + * at user time from scsi_scsi_cmd(), depending on whether + * there was a bp (basically, if there is a bp, there may be no + * associated process at the time. (it could be an async operation)) + * lower level routines shouldn't know about xs->bp.. we are the lowest. + */ static errval sc_err1(xs) struct scsi_xfer *xs; *************** *** 581,591 **** retval = ESUCCESS; if (bp) { bp->b_error = 0; ! bp->b_resid = 0; } break; case XS_SENSE: retval = scsi_interpret_sense(xs); if (retval == SCSIRET_DO_RETRY) { if (xs->retries--) { --- 631,660 ---- retval = ESUCCESS; if (bp) { bp->b_error = 0; ! bp->b_resid = 0; /* assume all data transferred */ ! } ! /* ! * if it appears untouched, ! * assume done ! * (don't we trust the adapter drivers to do this?) ! */ ! if(!(xs->flags & SCSI_RESID_VALID) ! && (xs->resid == xs->datalen)) { ! xs->resid = 0; } break; case XS_SENSE: + /* + * The return here is tricky.. a device might + * return a sense which is not an error. A tape will return + * for a short read or EOF (for example) with no error but + * with sense info. The private error handler may have + * set the residual values up correctly, and should have + * set the SCSI_RESID_VALID flag. We need to + * tell physio not to retry for + * more data. We mustn't clobber that resid value. + */ retval = scsi_interpret_sense(xs); if (retval == SCSIRET_DO_RETRY) { if (xs->retries--) { *************** *** 593,609 **** xs->flags &= ~ITSDONE; goto retry; } } - retval = EIO; /* Too many retries */ if (bp) { ! bp->b_error = 0; ! bp->b_resid = 0; if (retval) { bp->b_flags |= B_ERROR; - bp->b_error = retval; bp->b_resid = bp->b_bcount; } SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_interpret_sense (bp) returned %d\n", retval)); } else { --- 662,713 ---- xs->flags &= ~ITSDONE; goto retry; } + retval = EIO; /* Too many retries */ + } + /* + * an EOF condition results in a VALID resid.. + */ + if(xs->flags & SCSI_EOF) { + xs->resid = xs->datalen; + xs->flags |= SCSI_RESID_VALID; } if (bp) { ! bp->b_error = retval; if (retval) { bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; + } else { + /* + * apparently it was not an error. + * The trick is that in this case, the error + * interpretting code could have set xs->resid + * to be something useful. + * if not, maybe the adapter driver did.. + * + * It may have been an EOF (resid == datalen) + * or a short read, ( 0 < resid < datalen ) + * or a corrected soft_error (resid == 0) + */ + if( xs->flags & SCSI_RESID_VALID) { + bp->b_resid = xs->resid; + /* + * if it's a short read, set the error + * bit but not the error value.. + * that's how FreeBSD indicates that. + */ + if(xs->resid + && (xs->resid != xs->datalen)) + bp->b_flags |= B_ERROR; + } else { + /* + * If nothing gives us a better value, + * assume we transfered all we wanted + */ + bp->b_resid = 0; + } } + SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_interpret_sense (bp) returned %d\n", retval)); } else { *************** *** 612,621 **** } break; ! case XS_BUSY: ! /*should somehow arange for a 1 sec delay here (how?) */ ! /* XXX tsleep(&localvar, priority, "foo", hz); ! that's how! */ case XS_TIMEOUT: /* * If we can, resubmit it to the adapter. --- 716,728 ---- } break; ! case XS_BUSY: /*XXX*/ ! /* should somehow arange for a 1 sec delay here (how?)[jre] ! * tsleep(&localvar, priority, "foo", hz); ! * that's how! [unknown] ! * no, we could be at interrupt context.. use ! * timeout(scsi_resubmit,xs,hz); [jre] (not implimenteed yet) ! */ case XS_TIMEOUT: /* * If we can, resubmit it to the adapter. *************** *** 827,842 **** errcode = (*sc_link->device->err_handler) (xs); if (errcode >= 0) return errcode; /* valid errno value */ switch(errcode) { ! case SCSIRET_DO_RETRY: /* Requested a retry */ return errcode; ! case SCSIRET_CONTINUE: /* Continue with default sense processing */ break; ! default: sc_print_addr(xs->sc_link); printf("unknown return code %d from sense handler.\n", errcode); --- 934,952 ---- errcode = (*sc_link->device->err_handler) (xs); if (errcode >= 0) + if(xs->flags & SCSI_EOF) { + xs->resid = xs->datalen; + } return errcode; /* valid errno value */ switch(errcode) { ! case SCSIRET_DO_RETRY: /* Requested a retry */ return errcode; ! case SCSIRET_CONTINUE: /* Continue with default sense processing */ break; ! default: sc_print_addr(xs->sc_link); printf("unknown return code %d from sense handler.\n", errcode); *************** *** 890,895 **** --- 1000,1009 ---- switch ((int)key) { case 0x0: /* NO SENSE */ case 0x1: /* RECOVERED ERROR */ + if(xs->flags & SCSI_EOF) { + xs->resid = xs->datalen; + return (ESUCCESS); + } if (xs->resid == xs->datalen) xs->resid = 0; /* not short read */ case 0xc: /* EQUAL */ *** 1.4 1995/03/25 01:22:38 --- scsiconf.h 1995/03/25 05:39:29 *************** *** 406,412 **** --- 406,414 ---- #define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */ #define SCSI_NOSTART 0x04 /* left over from ancient history */ #define SCSI_USER 0x08 /* Is a user cmd, call scsi_user_done */ + #define SCSI_ITSDONE 0x10 /* the transfer is as done as it gets */ #define ITSDONE 0x10 /* the transfer is as done as it gets */ + #define SCSI_INUSE 0x20 /* The scsi_xfer block is in use */ #define INUSE 0x20 /* The scsi_xfer block is in use */ #define SCSI_SILENT 0x40 /* Don't report errors to console */ #define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */ *************** *** 416,421 **** --- 418,425 ---- #define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */ #define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */ #define SCSI_ESCAPE 0x2000 /* Escape operation */ + #define SCSI_EOF 0x4000 /* The operation should return EOF */ + #define SCSI_RESID_VALID 0x8000 /* The resid field contains valid data */ /* * Escape op codes. This provides an extensible setup for operations #################end of patch########## +----------------------------------+ ______ _ __ | __--_|\ Julian Elischer | \ U \/ / On assignment | / \ julian@tfs.com +------>x USA \ in a very strange | ( OZ ) 300 lakeside Dr. oakland CA. \___ ___ | country ! +- X_.---._/ USA+(510) 645-3137(wk) \_/ \\ v