diff options
Diffstat (limited to 'sys/scsi/sd.c')
-rw-r--r-- | sys/scsi/sd.c | 664 |
1 files changed, 366 insertions, 298 deletions
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 15d229b..d24f28b 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,5 +1,5 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Written by Julian Elischer (julian@dialix.oz.au) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -12,9 +12,9 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - * $Id$ + * $Id: sd.c,v 1.10 93/08/26 21:09:44 julian Exp Locker: julian $ */ #define SPLSD splbio @@ -68,7 +68,9 @@ struct buf sd_buf_queue[NSD]; int sd_done(); int sdstrategy(); +#ifdef SDDEBUG int sd_debug = 0; +#endif /*SDDEBUG*/ struct scsi_xfer *sd_free_xfer[NSD]; int sd_xfer_block_wait[NSD]; @@ -103,7 +105,7 @@ struct sd_data #define SDOPEN 0x01 int openparts; /* one bit for each open partition */ unsigned int sd_start_of_unix; /* unix vs dos partitions */ -}sd_data[NSD]; +}*sd_data[NSD]; static int next_sd_unit = 0; @@ -123,9 +125,9 @@ struct scsi_switch *scsi_switch; struct scsi_xfer *sd_scsi_xfer; unit = next_sd_unit++; - sd = sd_data + unit; - dp = &(sd->params); +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("sdattach: "); +#endif /*SDDEBUG*/ /*******************************************************\ * Check we have the resources for another drive * \*******************************************************/ @@ -134,6 +136,18 @@ struct scsi_switch *scsi_switch; printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",(unit + 1),NSD); return(0); } + if(sd_data[unit]) + { + printf("sd%d: unit already has storage allocated!\n",unit); + return(0); + } + sd = sd_data[unit] = malloc(sizeof(struct sd_data),M_DEVBUF,M_NOWAIT); + if(!sd) + { + printf("malloc failed in sd.c\n"); + return(0); + } + dp = &(sd->params); /*******************************************************\ * Store information needed to contact our base driver * \*******************************************************/ @@ -179,9 +193,6 @@ struct scsi_switch *scsi_switch; dp->heads, dp->sectors, dp->secsiz); - /*******************************************************\ - * Set up the bufs for this device * - \*******************************************************/ sd->flags |= SDINIT; return; @@ -202,10 +213,12 @@ sdopen(dev) unit = UNIT(dev); part = PARTITION(dev); - sd = sd_data + unit; + sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" , dev, unit, NSD, part); +#endif /*SDDEBUG*/ /*******************************************************\ * Check the unit is legal * \*******************************************************/ @@ -231,51 +244,64 @@ sdopen(dev) && ( sd->openparts)) return(ENXIO); /*******************************************************\ - * Check that it is still responding and ok. * - * "unit attention errors should occur here if the drive * - * has been restarted or the pack changed * + * "unit attention" errors should occur here if the * + * drive has been restarted or the pack changed. * + * just ingnore the result, it's a decoy instruction * + * The error code will act on the error though * + * and invalidate any media information we had. * \*******************************************************/ + sd_test_unit_ready(unit,0); - if(scsi_debug & TRACEOPENS) - printf("device is "); - if (sd_test_unit_ready(unit,0)) - { - if(scsi_debug & TRACEOPENS) printf("not reponding\n"); - return(ENXIO); - } - if(scsi_debug & TRACEOPENS) - printf("ok\n"); /*******************************************************\ * In case it is a funny one, tell it to start * * not needed for most hard drives (ignore failure) * \*******************************************************/ sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT); + + /*******************************************************\ + * Check that it is still responding and ok. * + \*******************************************************/ + if (sd_test_unit_ready(unit,0)) + { +#ifdef SDDEBUG + if(scsi_debug & TRACEOPENS) printf("device not reponding\n"); +#endif /*SDDEBUG*/ + return(ENXIO); + } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) - printf("started "); + printf("device ok\n"); +#endif /*SDDEBUG*/ + /*******************************************************\ * Load the physical device parameters * \*******************************************************/ sd_get_parms(unit, 0); /* sets SDVALID */ - if (sd->params.secsiz != SECSIZE) + if (sd->params.secsiz != SECSIZE) /* XXX One day...*/ { printf("sd%d: Can't deal with %d bytes logical blocks\n" ,unit, sd->params.secsiz); Debugger(); return(ENXIO); } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("Params loaded "); +#endif /*SDDEBUG*/ /*******************************************************\ * Load the partition info if not already loaded * + * Lock the pack in * \*******************************************************/ - sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); return(errcode); } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("Disklabel loaded "); +#endif /*SDDEBUG*/ /*******************************************************\ * Check the partition is legal * \*******************************************************/ @@ -283,8 +309,10 @@ sdopen(dev) sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ return(ENXIO); } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("ok"); +#endif /*SDDEBUG*/ /*******************************************************\ * Check that the partition exists * \*******************************************************/ @@ -296,8 +324,10 @@ sdopen(dev) } sd->partflags[part] |= SDOPEN; sd->openparts |= (1 << part); +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("open %d %d\n",sdstrats,sdqueues); +#endif /*SDDEBUG*/ return(0); } @@ -377,7 +407,7 @@ int flags; void sdminphys(bp) struct buf *bp; { - (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); + (*(sd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); } /*******************************************************\ @@ -397,10 +427,12 @@ struct buf *bp; sdstrats++; unit = UNIT((bp->b_dev)); - sd = sd_data + unit; + sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy "); if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n", unit,bp->b_bcount,bp->b_blkno); +#endif /*SDDEBUG*/ sdminphys(bp); /*******************************************************\ * If the device has been made invalid, error out * @@ -477,7 +509,7 @@ done: /***************************************************************\ * sdstart looks to see if there is a buf waiting for the device * * and that the device is not already busy. If both are true, * -* It deques the buf and creates a scsi command to perform the * +* It dequeues the buf and creates a scsi command to perform the * * transfer in the buf. The transfer request will call sd_done * * on completion, which will in turn call this routine again * * so that the next queued transfer is performed. * @@ -499,37 +531,41 @@ int unit; struct scsi_xfer *xs; struct scsi_rw_big cmd; int blkno, nblk; - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; struct partition *p ; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit); +#endif /*SDDEBUG*/ /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * + * Check if the device is already running full capacity * \*******************************************************/ if(!sd_free_xfer[unit]) { return; /* none for us, unit already underway */ } - if(sd_xfer_block_wait[unit]) /* there is one, but a special waits */ + /*******************************************************\ + * there is excess capacity, but a special waits * + * It'll need the adapter as soon as we clear out of the * + * way and let it run (user level wait). * + \*******************************************************/ + if(sd_xfer_block_wait[unit]) { - return; /* give the special that's waiting a chance to run */ + return; } - + /*******************************************************\ + * See if there is a buf with work for us to do.. * + \*******************************************************/ dp = &sd_buf_queue[unit]; - if ((bp = dp->b_actf) != NULL) /* yes, an assign */ + if ((bp = dp->b_actf) == NULL) /* yes, an assign */ { - dp->b_actf = bp->av_forw; - } - else - { return; } - xs=sd_get_xs(unit,0); /* ok we can grab it */ - xs->flags = INUSE; /* Now ours */ + dp->b_actf = bp->av_forw; + /*******************************************************\ * If the device has become invalid, abort all the * * reads and writes until all files have been closed and * @@ -537,15 +573,12 @@ int unit; \*******************************************************/ if(!(sd->flags & SDVALID)) { - xs->error = XS_DRIVER_STUFFUP; - sd_done(unit,xs); /* clean up (calls sdstart) */ - return ; + goto bad; } /*******************************************************\ - * We have a buf, now we should move the data into * - * a scsi_xfer definition and try start it * - \*******************************************************/ - /*******************************************************\ + * We have a buf, now we know we are going to go through * + * With this thing.. * + * * * First, translate the block to absolute * \*******************************************************/ p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); @@ -565,112 +598,31 @@ int unit; cmd.length2 = (nblk & 0xff00) >> 8; cmd.length1 = (nblk & 0xff); /*******************************************************\ - * Fill out the scsi_xfer structure * + * Call the routine that chats with the adapter * * Note: we cannot sleep as we may be an interrupt * \*******************************************************/ - xs->flags |= SCSI_NOSLEEP; - xs->adapter = sd->ctlr; - xs->targ = sd->targ; - xs->lu = sd->lu; - xs->retries = SD_RETRIES; - xs->timeout = 10000;/* 10000 millisecs for a disk !*/ - xs->cmd = (struct scsi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->resid = bp->b_bcount; - xs->when_done = sd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->error = XS_NOERROR; - xs->bp = bp; - xs->data = (u_char *)bp->b_un.b_addr; - xs->datalen = bp->b_bcount; - /*******************************************************\ - * Pass all this info to the scsi driver. * - \*******************************************************/ - - - - if ( (*(sd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) + if (sd_scsi_cmd(unit, + &cmd, + sizeof(cmd), + (u_char *)bp->b_un.b_addr, + bp->b_bcount, + 10000, + bp, + SCSI_NOSLEEP| ((bp->b_flags & B_READ)? + SCSI_DATA_IN : SCSI_DATA_OUT)) + != SUCCESSFULLY_QUEUED) { +bad: printf("sd%d: oops not queued",unit); - xs->error = XS_DRIVER_STUFFUP; - sd_done(unit,xs); /* clean up (calls sdstart) */ + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return ; } sdqueues++; } /*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int sd_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - int retries = 0; - - if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); - if (! (xs->flags & INUSE)) - panic("scsi_xfer not in use!"); - if(bp = xs->bp) - { - switch(xs->error) - { - case XS_NOERROR: - bp->b_error = 0; - bp->b_resid = 0; - break; - - case XS_SENSE: - retval = (sd_interpret_sense(unit,xs)); - if(retval) - { - bp->b_flags |= B_ERROR; - bp->b_error = retval; - } - break; - - case XS_TIMEOUT: - printf("sd%d timeout\n",unit); - - case XS_BUSY: /* should retry */ /* how? */ - /************************************************/ - /* SHOULD put buf back at head of queue */ - /* and decrement retry count in (*xs) */ - /* HOWEVER, this should work as a kludge */ - /************************************************/ - if(xs->retries--) - { - xs->error = XS_NOERROR; - xs->flags &= ~ITSDONE; - if ( (*(sd_data[unit].sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* don't wake the job, ok? */ - return; - } - xs->flags |= ITSDONE; - } /* fall through */ - - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("sd%d: unknown error category from scsi driver\n" - ,unit); - } - biodone(bp); - sd_free_xs(unit,xs,0); - sdstart(unit); /* If there's anything waiting.. do it */ - } - else /* special has finished */ - { - wakeup(xs); - } -} -/*******************************************************\ * Perform special action on behalf of the user * * Knows about the internals of this device * \*******************************************************/ @@ -688,13 +640,15 @@ sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) \*******************************************************/ unit = UNIT(dev); part = PARTITION(dev); - sd = &sd_data[unit]; + sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit); +#endif /*SDDEBUG*/ /*******************************************************\ * If the device is not valid.. abandon ship * \*******************************************************/ - if (!(sd_data[unit].flags & SDVALID)) + if (!(sd->flags & SDVALID)) return(EIO); switch(cmd) { @@ -778,7 +732,7 @@ unsigned char unit; /*unsigned int n, m;*/ char *errstring; struct dos_partition *dos_partition_p; - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; /*******************************************************\ * If the inflo is already loaded, use it * @@ -789,6 +743,7 @@ unsigned char unit; /*******************************************************\ * make partition 3 the whole disk in case of failure * * then get pdinfo * + * for historical reasons, make part a same as raw part * \*******************************************************/ sd->disklabel.d_partitions[0].p_offset = 0; sd->disklabel.d_partitions[0].p_size = sd->params.disksize; @@ -804,11 +759,11 @@ unsigned char unit; { sd->disklabel.d_secpercyl = 100; /* as long as it's not 0 */ - /* readdisklabel divides by it */ + /* readdisklabel divides by it (?)*/ } /*******************************************************\ - * all the generic disklabel extraction routine * + * Call the generic disklabel extraction routine * \*******************************************************/ if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3) , sdstrategy @@ -820,9 +775,6 @@ unsigned char unit; printf("sd%d: %s\n",unit, errstring); return(ENXIO); } - /*******************************************************\ - * leave partition 2 "open" for raw I/O * - \*******************************************************/ sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ return(ESUCCESS); @@ -854,7 +806,8 @@ sd_size(unit, flags) &rdcap, sizeof(rdcap), 2000, - flags) != 0) + NULL, + flags | SCSI_DATA_IN) != 0) { printf("sd0%: could not get size\n", unit); return(0); @@ -884,17 +837,21 @@ int unit,flags; 0, 0, 100000, + NULL, flags)); } /*******************************************************\ * Prevent or allow the user to remove the tape * +* Don't change this status if any partitions are open * \*******************************************************/ sd_prevent(unit,type,flags) int unit,type,flags; { struct scsi_prevent scsi_cmd; + if(sd_data[unit]->openparts) return; + bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PREVENT_ALLOW; scsi_cmd.how=type; @@ -904,6 +861,7 @@ int unit,type,flags; 0, 0, 5000, + NULL, flags) ); } /*******************************************************\ @@ -924,6 +882,7 @@ int unit,flags; 0, 0, 2000, + NULL, flags)); } @@ -953,7 +912,8 @@ sd_reassign_blocks(unit,block) &rbdata, sizeof(rbdata), 5000, - 0)); + NULL, + SCSI_DATA_OUT)); } #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) @@ -966,7 +926,7 @@ sd_reassign_blocks(unit,block) int sd_get_parms(unit, flags) { - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; struct disk_parms *disk_parms = &sd->params; struct scsi_mode_sense scsi_cmd; struct scsi_mode_sense_data @@ -984,6 +944,7 @@ int sd_get_parms(unit, flags) /*******************************************************\ * First do a mode sense page 3 * \*******************************************************/ +#ifdef SDDEBUG if (sd_debug) { bzero(&scsi_cmd, sizeof(scsi_cmd)); @@ -1000,11 +961,13 @@ int sd_get_parms(unit, flags) &scsi_sense, sizeof(scsi_sense), 2000, - flags) != 0) + NULL, + flags | SCSI_DATA_IN) != 0) { printf("sd%d: could not mode sense (3)\n", unit); - return(ENXIO); } + else + { printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n", unit, b2tol(scsi_sense.pages.disk_format.trk_z), @@ -1017,7 +980,9 @@ int sd_get_parms(unit, flags) b2tol(scsi_sense.pages.disk_format.interleave), sd_size(unit, flags), _3btol(scsi_sense.blk_desc.blklen)); + } } +#endif /*SDDEBUG*/ /*******************************************************\ @@ -1037,14 +1002,15 @@ int sd_get_parms(unit, flags) &scsi_sense, sizeof(scsi_sense), 2000, - flags) != 0) + NULL, + flags | SCSI_DATA_IN) != 0) { - printf("sd%d: could not mode sense (4)", unit); - printf(" using ficticious geometry\n"); + printf("sd%d could not mode sense (4).", unit); + printf(" Using ficticious geometry\n"); /* * use adaptec standard ficticious geometry - * this depends on controllers and mode (ie, 1542C in - * extended bios translation is different + * this depends on which controller (e.g. 1542C is + * different. but we have to put SOMETHING here..) */ sectors = sd_size(unit, flags); disk_parms->heads = 64; @@ -1055,6 +1021,8 @@ int sd_get_parms(unit, flags) } else { + +#ifdef SDDEBUG if (sd_debug) { printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", @@ -1064,11 +1032,13 @@ int sd_get_parms(unit, flags) b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), b2tol(scsi_sense.pages.rigid_geometry.land_zone)); } +#endif /*SDDEBUG*/ /*******************************************************\ * KLUDGE!!(for zone recorded disks) * * give a number of sectors so that sec * trks * cyls * * is <= disk_size * + * can lead to wasted space! THINK ABOUT THIS ! * \*******************************************************/ disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads; disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2); @@ -1076,8 +1046,8 @@ int sd_get_parms(unit, flags) sectors = sd_size(unit, flags); disk_parms->disksize = sectors; - sectors /= (disk_parms->cyls * disk_parms->heads); - disk_parms->sectors = sectors; /* dubious on SCSI*/ + sectors /= (disk_parms->heads * disk_parms->cyls); + disk_parms->sectors = sectors; /* dubious on SCSI*//*XXX*/ } sd->flags |= SDVALID; @@ -1087,22 +1057,110 @@ int sd_get_parms(unit, flags) /*******************************************************\ * close the device.. only called if we are the LAST * * occurence of an open device * +* convenient now but usually a pain * \*******************************************************/ sdclose(dev) dev_t dev; { unsigned char unit, part; unsigned int old_priority; + struct sd_data *sd; unit = UNIT(dev); part = PARTITION(dev); - sd_data[unit].partflags[part] &= ~SDOPEN; - sd_data[unit].openparts &= ~(1 << part); - if(sd_data[unit].openparts == 0) /* if all partitions closed */ + sd = sd_data[unit]; + sd->partflags[part] &= ~SDOPEN; + sd->openparts &= ~(1 << part); + sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); + return(0); +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int sd_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + int retries = 0; + +#ifdef SDDEBUG + if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); +#endif /*SDDEBUG*/ +#ifdef PARANOID + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); +#endif + if((bp = xs->bp) == NULL) { - sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); + /***********************************************\ + * if it's a normal user level request, then ask * + * The user level code to handle error checking * + * rather than doing it here at interrupt time * + \***********************************************/ + wakeup(xs); + return; } - return(0); + + /***********************************************\ + * If it has a buf, we might be working with * + * a request from the buffer cache or some other * + * piece of code that requires us to process * + * errors right now, despite cost * + \***********************************************/ + switch(xs->error) + { + case XS_NOERROR: + bp->b_error = 0; + bp->b_resid = 0; + break; + + case XS_SENSE: + retval = (sd_interpret_sense(unit,xs)); + if(retval) + { + bp->b_flags |= B_ERROR; + bp->b_error = retval; + } + break; + + case XS_BUSY: + /*should somehow arange for a 1 sec delay here (how?)*/ + case XS_TIMEOUT: + /***********************************************\ + * If we can, resubmit it to the adapter. * + \***********************************************/ + if(xs->retries--) + { + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + if ( (*(sd_data[unit]->sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* don't wake the job, ok? */ + return; + } + xs->flags |= ITSDONE; + } /* fall through */ + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("sd%d: unknown error category from scsi driver\n" + ,unit); + } + /*******************************\ + * tell the owner we're done * + * then free our resources * + * and see if there's more work * + \*******************************/ + biodone(bp); + sd_free_xs(unit,xs,0); + sdstart(unit); /* If there's anything waiting.. do it */ } /*******************************************************\ @@ -1110,11 +1168,12 @@ dev_t dev; * Call it through the switch table, and tell it which * * sub-unit we want, and what target and lu we wish to * * talk to. Also tell it where to find the command * -* how long int is. * +* and how long it is. * * Also tell it where to read/write the data, and how * -* long the data is supposed to be * +* long the data is supposed to be. If we have a buf * +* to associate with the transfer, we need that too. * \*******************************************************/ -int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) +int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) int unit,flags; struct scsi_generic *scsi_cmd; @@ -1122,112 +1181,136 @@ int cmdlen; int timeout; u_char *data_addr; int datalen; +struct buf *bp; { struct scsi_xfer *xs; int retval; int s; - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit); - if(sd->sc_sw) /* If we have a scsi driver */ +#endif /*SDDEBUG*/ + +#ifdef PARANOID + if(!(sd->sc_sw)) /* If we have a scsi driver */ + {/* How we got here is anyone's guess */ + printf("sd%d: not set up\n",unit); + return(EINVAL); + } +#endif + xs = sd_get_xs(unit,flags); /* should wait unless booting */ +#ifdef PARANOID + if(!xs) { - xs = sd_get_xs(unit,flags); /* should wait unless booting */ - if(!xs) - { - printf("sd_scsi_cmd%d: controller busy" - " (this should never happen)\n",unit); - return(EBUSY); - } - xs->flags |= INUSE; - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = sd->ctlr; - xs->targ = sd->targ; - xs->lu = sd->lu; - xs->retries = SD_RETRIES; - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = (flags & SCSI_NOMASK) - ?(int (*)())0 - :sd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; -retry: xs->error = XS_NOERROR; - xs->bp = 0; - retval = (*(sd->sc_sw->scsi_cmd))(xs); - switch(retval) - { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); + printf("sd_scsi_cmd%d: controller busy" + " (this should never happen)\n",unit); + return(EBUSY); + } +#endif + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags = INUSE | flags; + xs->adapter = sd->ctlr; + xs->targ = sd->targ; + xs->lu = sd->lu; + xs->retries = SD_RETRIES; + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = sd_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->bp = bp; +retry: xs->error = XS_NOERROR; - case HAD_ERROR: - /*printf("err = %d ",xs->error);*/ - switch(xs->error) - { - case XS_NOERROR: - retval = ESUCCESS; - break; - case XS_SENSE: - retval = (sd_interpret_sense(unit,xs)); - break; - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - case XS_BUSY: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - default: - retval = EIO; - printf("sd%d: unknown error category from scsi driver\n" - ,unit); - } - break; - case COMPLETE: + /*******************************************************\ + * Do the transfer. If we are polling we will return: * + * COMPLETE, Was poll, and sd_done has been called * + * HAD_ERROR, Was poll and an error was encountered * + * TRY_AGAIN_LATER, Adapter short resources, try again * + * * + * if under full steam (interrupts) it will return: * + * SUCCESSFULLY_QUEUED, will do a wakeup when complete * + * HAD_ERROR, had an erro before it could queue * + * TRY_AGAIN_LATER, (as for polling) * + * After the wakeup, we must still check if it succeeded * + * * + * If we have a bp however, all the error proccessing * + * and the buffer code both expect us to return straight * + * to them, so as soon as the command is queued, return * + \*******************************************************/ + retval = (*(sd->sc_sw->scsi_cmd))(xs); + if(bp) return retval; /* will sleep (or not) elsewhere */ + + /*******************************************************\ + * Only here for non I/O cmds. It's cheaper to process * + * the error status here than at interrupt time so * + * sd_done will have done nothing except wake us up. * + \*******************************************************/ + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + /* fall through to check success of completed command */ + + case HAD_ERROR: + switch(xs->error) + { + case XS_NOERROR: /* nearly always hit this one */ retval = ESUCCESS; break; - case TRY_AGAIN_LATER: + + case XS_SENSE: + retval = (sd_interpret_sense(unit,xs)); + break; + case XS_BUSY: + /* should sleep 1 sec here */ + case XS_TIMEOUT: if(xs->retries-- ) { xs->flags &= ~ITSDONE; goto retry; } + case XS_DRIVER_STUFFUP: retval = EIO; break; default: retval = EIO; + printf("sd%d: unknown error category from scsi driver\n" + ,unit); + } + break; + case COMPLETE: /* Polling command completed ok */ + retval = ESUCCESS; + break; + + case TRY_AGAIN_LATER: /* adapter resource shortage */ + /* should sleep 1 sec here */ + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; } - sd_free_xs(unit,xs,flags); - sdstart(unit); /* check if anything is waiting fr the xs */ - } - else - { - printf("sd%d: not set up\n",unit); - return(EINVAL); + default: + retval = EIO; } + /*******************************************************\ + * we have finished with the xfer stuct, free it and * + * check if anyone else needs to be started up. * + \*******************************************************/ + sd_free_xs(unit,xs,flags); + sdstart(unit); /* check queue */ return(retval); } + /***************************************************************\ * Look at the returned sense and act on the error and detirmine * * The unix error number to pass back... (0 = report no error) * @@ -1240,6 +1323,7 @@ struct scsi_xfer *xs; struct scsi_sense_data *sense; int key; int silent; + long int info; /***************************************************************\ * If the flags say errs are ok, then always return ok. * @@ -1248,6 +1332,10 @@ struct scsi_xfer *xs; silent = (xs->flags & SCSI_SILENT); sense = &(xs->sense); + info = ((sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); switch(sense->error_code & SSD_ERRCODE) { case 0x70: @@ -1263,11 +1351,7 @@ struct scsi_xfer *xs; printf("sd%d: soft error(corrected) ", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)",info); } printf("\n"); } @@ -1282,11 +1366,7 @@ struct scsi_xfer *xs; printf("sd%d: medium error ", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)",info); } printf("\n"); } @@ -1306,8 +1386,8 @@ struct scsi_xfer *xs; * sure that we don't have any residual state * \***********************************************/ if(!silent)printf("sd%d: Unit attention.\n ", unit); - sd_data[unit].flags &= ~(SDVALID | SDHAVELABEL); - if (sd_data[unit].openparts) + sd_data[unit]->flags &= ~(SDVALID | SDHAVELABEL); + if (sd_data[unit]->openparts) { return(EIO); } @@ -1319,11 +1399,7 @@ struct scsi_xfer *xs; unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1331,15 +1407,11 @@ struct scsi_xfer *xs; case 0x8: if(!silent) { - printf("sd%d: block wrong state (worm)\n ", + printf("sd%d: block wrong state (format?)\n ", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1363,11 +1435,7 @@ struct scsi_xfer *xs; unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1383,11 +1451,7 @@ struct scsi_xfer *xs; unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1426,7 +1490,8 @@ sdsize(dev_t dev) if (unit >= NSD) return(-1); - sd = &sd_data[unit]; + sd = sd_data[unit]; + if(!sd) return(-1); if((sd->flags & SDINIT) == 0) return(-1); if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0); @@ -1435,7 +1500,7 @@ sdsize(dev_t dev) return((int)sd->disklabel.d_partitions[part].p_size); } - +/*#define SCSIDUMP*/ #ifdef SCSIDUMP #include <vm/vm.h> /***********************************************************************\ @@ -1473,7 +1538,8 @@ sddump(dev_t dev) /* dump core after a system crash */ /* check for acceptable drive number */ if (unit >= NSD) return(ENXIO); /* 31 Jul 92*/ - sd = sd_data+unit; + sd = sd_data[unit]; + if(!sd) return (ENXIO); /* was it ever initialized etc. ? */ if (!(sd->flags & SDINIT)) return (ENXIO); if (sd->flags & SDVALID != SDVALID) return (ENXIO) ; @@ -1503,7 +1569,7 @@ sddump(dev_t dev) /* dump core after a system crash */ trunc_page(addr), VM_PROT_READ, TRUE); -#ifndef NOT_TRUSTED +#ifndef NOT_TRUSTED /*******************************************************\ * Fill out the scsi command * \*******************************************************/ @@ -1552,8 +1618,9 @@ sddump(dev_t dev) /* dump core after a system crash */ return(ENXIO); /* we said not to sleep! */ } #else NOT_TRUSTED + /* lets just talk about this first...*/ printf ("sd%d: dump addr 0x%x, blk %d\n",unit,addr,blknum); -#endif +#endif NOT_TRUSTED if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ; /* update block count */ @@ -1567,11 +1634,12 @@ sddump(dev_t dev) /* dump core after a system crash */ } return(0); } -#else /* No SCSIDUMP CODE */ +#else SCSIDUMP sddump() { printf("\nsddump() -- not implemented\n"); - DELAY(20000000); /* 100 seconds */ + DELAY(100000000); /* 100 seconds */ return(-1); } -#endif +#endif SCSIDUMP + |