X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/15637ed4f028f1b013a54c226bcb3c75228ad20d..795abf1316db53d4abdc5bff180f2b2376c5cfe4:/sys/scsi/sd.c diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index af8ae79176..22dce9a788 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,20 +12,9 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 2 00149 - * -------------------- ----- ---------------------- - * - * 16 Feb 93 Julian Elischer ADDED for SCSI system - * 20 Apr 93 Julian Elischer Fixed error reporting + * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - */ - -static char rev[] = "$Revision: 1.3 $"; - -/* - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * $Id: sd.c,v 1.26 1994/05/26 00:23:24 jkh Exp $ */ #define SPLSD splbio @@ -33,6 +22,7 @@ static char rev[] = "$Revision: 1.3 $"; #include #include #include +#include #include #include #include @@ -47,25 +37,32 @@ static char rev[] = "$Revision: 1.3 $"; #include #include #include +#include -long int sdstrats,sdqueues; - +u_int32 sdstrats, sdqueues; +#ifdef NetBSD +#ifdef DDB +int Debugger(); +#else /* DDB */ +#define Debugger() +#endif /* DDB */ +#else /* NetBSD */ #include #if NDDB > 0 -int Debugger(); -#else NDDB > 0 -#define Debugger() -#endif NDDB > 0 - +#else /* NDDB > 0 */ +#define Debugger(s) +#endif /* NDDB > 0 */ +#endif #define PAGESIZ 4096 #define SECSIZE 512 -#define PDLOCATION 29 +#define PDLOCATION 29 #define BOOTRECORDSIGNATURE (0x55aa & 0x00ff) #define SDOUTSTANDING 2 #define SDQSIZE 4 #define SD_RETRIES 4 +#define MAXTRANSFER 8 /* 1 page at a time */ #define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part))) #define UNITSHIFT 3 @@ -75,881 +72,717 @@ int Debugger(); #define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART ) -struct buf sd_buf_queue[NSD]; -int sd_done(); -int sdstrategy(); - -int sd_debug = 0; - -struct scsi_xfer *sd_free_xfer[NSD]; -int sd_xfer_block_wait[NSD]; +errval sdgetdisklabel __P((unsigned char unit)); +errval sd_get_parms __P((int unit, int flags)); +void sdstrategy __P((struct buf *)); +void sdstart __P((u_int32)); -struct sd_data +struct scsi_device sd_switch = { - int flags; -#define SDVALID 0x02 /* PARAMS LOADED */ -#define SDINIT 0x04 /* device has been init'd */ -#define SDWAIT 0x08 /* device has someone waiting */ -#define SDHAVELABEL 0x10 /* have read the label */ -#define SDDOSPART 0x20 /* Have read the DOS partition table */ -#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/ - struct scsi_switch *sc_sw; /* address of scsi low level switch */ - int ctlr; /* so they know which one we want */ - int targ; /* our scsi target ID */ - int lu; /* out scsi lu */ - long int ad_info; /* info about the adapter */ - int cmdscount; /* cmds allowed outstanding by board*/ - int wlabel; /* label is writable */ - struct disk_parms - { - u_char heads; /* Number of heads */ - u_short cyls; /* Number of cylinders */ - u_char sectors;/*dubious*/ /* Number of sectors/track */ - u_short secsiz; /* Number of bytes/sector */ - u_long disksize; /* total number sectors */ - }params; - struct disklabel disklabel; - struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */ - int partflags[MAXPARTITIONS]; /* per partition flags */ + NULL, /* Use default error handler */ + sdstart, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "sd", + 0, + { 0, 0 } +}; + +struct sd_data { + u_int32 flags; +#define SDINIT 0x04 /* device has been init'd */ +#define SDHAVELABEL 0x10 /* have read the label */ +#define SDDOSPART 0x20 /* Have read the DOS partition table */ +#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W) */ + struct scsi_link *sc_link; /* contains our targ, lun etc. */ + u_int32 ad_info; /* info about the adapter */ + u_int32 cmdscount; /* cmds allowed outstanding by board */ + boolean wlabel; /* label is writable */ + struct disk_parms { + u_char heads; /* Number of heads */ + u_int16 cyls; /* Number of cylinders */ + u_char sectors; /*dubious *//* Number of sectors/track */ + u_int16 secsiz; /* Number of bytes/sector */ + u_int32 disksize; /* total number sectors */ + } params; + struct disklabel disklabel; +#ifdef NetBSD + struct cpu_disklabel cpudisklabel; +#else + struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */ +#endif /* NetBSD */ + u_int32 partflags[MAXPARTITIONS]; /* per partition flags */ #define SDOPEN 0x01 - int openparts; /* one bit for each open partition */ - unsigned int sd_start_of_unix; /* unix vs dos partitions */ -}sd_data[NSD]; + u_int32 openparts; /* one bit for each open partition */ + u_int32 sd_start_of_unix; /* unix vs dos partitions */ + struct buf buf_queue; + u_int32 xfer_block_wait; +} *sd_data[NSD]; +static u_int32 next_sd_unit = 0; -static int next_sd_unit = 0; -/***********************************************************************\ -* The routine called by the low level scsi routine when it discovers * -* A device suitable for this driver * -\***********************************************************************/ +static struct scsi_xfer sx; -int sdattach(ctlr,targ,lu,scsi_switch) -struct scsi_switch *scsi_switch; +/* + * The routine called by the low level scsi routine when it discovers + * a device suitable for this driver. + */ +errval +sdattach(sc_link) + struct scsi_link *sc_link; { - int unit,i; - unsigned char *tbl; + u_int32 unit; struct sd_data *sd; struct disk_parms *dp; - long int ad_info; - struct scsi_xfer *sd_scsi_xfer; unit = next_sd_unit++; - sd = sd_data + unit; - dp = &(sd->params); - if(scsi_debug & PRINTROUTINES) printf("sdattach: "); - /*******************************************************\ - * Check we have the resources for another drive * - \*******************************************************/ - if( unit >= NSD) - { - printf("Too many scsi disks..(%d > %d) reconfigure kernel",(unit + 1),NSD); - return(0); + SC_DEBUG(sc_link, SDEV_DB2, ("sdattach: ")); + /* + * Check we have the resources for another drive + */ + if (unit >= NSD) { + 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; } - /*******************************************************\ - * Store information needed to contact our base driver * - \*******************************************************/ - sd->sc_sw = scsi_switch; - sd->ctlr = ctlr; - sd->targ = targ; - sd->lu = lu; - if(sd->sc_sw->adapter_info) - { - sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr)); - sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS; - if(sd->cmdscount > SDOUTSTANDING) - { + sd = sd_data[unit] = malloc(sizeof(struct sd_data), M_DEVBUF, M_NOWAIT); + if (!sd) { + printf("malloc failed in sd.c\n"); + return (0); + } + bzero(sd, sizeof(struct sd_data)); + + dp = &(sd->params); + /* + * Store information needed to contact our base driver + */ + sd->sc_link = sc_link; + sc_link->device = &sd_switch; + sc_link->dev_unit = unit; + + if (sd->sc_link->adapter->adapter_info) { + sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit)); + sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS; + if (sd->cmdscount > SDOUTSTANDING) { sd->cmdscount = SDOUTSTANDING; } - } - else - { + } else { sd->ad_info = 1; - sd->cmdscount = 1; - } - - i = sd->cmdscount; - sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i - ,M_TEMP, M_NOWAIT); - while(i-- ) - { - sd_scsi_xfer->next = sd_free_xfer[unit]; - sd_free_xfer[unit] = sd_scsi_xfer; - sd_scsi_xfer++; - } - /*******************************************************\ - * Use the subdriver to request information regarding * - * the drive. We cannot use interrupts yet, so the * - * request must specify this. * - \*******************************************************/ - sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); - printf(" sd%d: %dMB, cyls %d, heads %d, secs %d, bytes/sec %d\n", - unit, - ( dp->cyls - * dp->heads - * dp->sectors - * dp->secsiz - ) - / (1024 * 1024), - dp->cyls, - dp->heads, - dp->sectors, - dp->secsiz); - /*******************************************************\ - * Set up the bufs for this device * - \*******************************************************/ + sd->cmdscount = 1; + } + sc_link->opennings = sd->cmdscount; + /* + * Use the subdriver to request information regarding + * the drive. We cannot use interrupts yet, so the + * request must specify this. + */ + sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); + printf("sd%d: %dMB (%d total sec), %d cyl, %d head, %d sec, bytes/sec %d\n", + unit, + dp->disksize / ((1024L * 1024L) / dp->secsiz), + dp->disksize, + dp->cyls, + dp->heads, + dp->sectors, + dp->secsiz); sd->flags |= SDINIT; - return; - + return 0; } - - -/*******************************************************\ -* open the device. Make sure the partition info * -* is a up-to-date as can be. * -\*******************************************************/ +/* + * open the device. Make sure the partition info is a up-to-date as can be. + */ +errval sdopen(dev) + int dev; /* XXX should be dev_t, but avoid promotion problems for now */ { - int errcode = 0; - int unit, part; - struct disk_parms disk_parms; - struct sd_data *sd ; + errval errcode = 0; + u_int32 unit, part; + struct sd_data *sd; + struct scsi_link *sc_link; unit = UNIT(dev); part = PARTITION(dev); - sd = sd_data + unit; - if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) - printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" - , dev, unit, NSD, part); - /*******************************************************\ - * Check the unit is legal * - \*******************************************************/ - if ( unit >= NSD ) - { - return(ENXIO); + sd = sd_data[unit]; + /* + * Check the unit is legal + */ + if (unit >= NSD) { + return (ENXIO); } - /*******************************************************\ - * Make sure the disk has been initialised * - * At some point in the future, get the scsi driver * - * to look for a new device if we are not initted * - \*******************************************************/ - if (! (sd->flags & SDINIT)) - { - return(ENXIO); + /* + * Make sure the disk has been initialised + * At some point in the future, get the scsi driver + * to look for a new device if we are not initted + */ + if ((!sd) || (!(sd->flags & SDINIT))) { + return (ENXIO); } + sc_link = sd->sc_link; + + SC_DEBUG(sc_link, SDEV_DB1, + ("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" + ,dev, unit, NSD, part)); + + /* + * "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. + */ + scsi_test_unit_ready(sc_link, 0); + + /* + * If it's been invalidated, then forget the label + */ + sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + sd->flags &= ~SDHAVELABEL; - /*******************************************************\ - * If it's been invalidated, and not everybody has * - * closed it then forbid re-entry. * - \*******************************************************/ - if ((! (sd->flags & SDVALID)) - && ( 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 * - \*******************************************************/ - - 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 somebody still has it open, then forbid re-entry. + */ + if (sd->openparts) { + errcode = ENXIO; + goto bad; + } } - 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); - if(scsi_debug & TRACEOPENS) - printf("started "); - /*******************************************************\ - * Load the physical device parameters * - \*******************************************************/ - sd_get_parms(unit, 0); /* sets SDVALID */ - if (sd->params.secsiz != SECSIZE) - { - printf("sd%d: Can't deal with %d bytes logical blocks\n" - ,unit, sd->params.secsiz); - Debugger(); - return(ENXIO); + /* + * In case it is a funny one, tell it to start + * not needed for most hard drives (ignore failure) + */ + scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT); + + /* + * Check that it is still responding and ok. + */ + if (scsi_test_unit_ready(sc_link, 0)) { + SC_DEBUG(sc_link, SDEV_DB3, ("device not reponding\n")); + errcode = ENXIO; + goto bad; } - if(scsi_debug & TRACEOPENS) - printf("Params loaded "); - /*******************************************************\ - * Load the partition info if not already loaded * - \*******************************************************/ - sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ - if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) - { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ - return(errcode); + SC_DEBUG(sc_link, SDEV_DB3, ("device ok\n")); + + /* + * Load the physical device parameters + */ + sd_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */ + 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("sd"); + errcode = ENXIO; + goto bad; + } + SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded ")); + + /* Lock the pack in. */ + scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT); + + /* + * Load the partition info if not already loaded. + */ + if ((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) { + goto bad; } - if(scsi_debug & TRACEOPENS) - printf("Disklabel loaded "); - /*******************************************************\ - * Check the partition is legal * - \*******************************************************/ - if ( part >= MAXPARTITIONS ) { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ - return(ENXIO); + SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded ")); + /* + * Check the partition is legal + */ + if (part >= MAXPARTITIONS) { + errcode = ENXIO; + goto bad; } - if(scsi_debug & TRACEOPENS) - printf("ok"); - /*******************************************************\ - * Check that the partition exists * - \*******************************************************/ - if (( sd->disklabel.d_partitions[part].p_size == 0 ) - && (part != RAW_PART)) - { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ - return(ENXIO); + SC_DEBUG(sc_link, SDEV_DB3, ("partition ok")); + + /* + * Check that the partition exists + */ + if ((sd->disklabel.d_partitions[part].p_size == 0) + && (part != RAW_PART)) { + errcode = ENXIO; + goto bad; } sd->partflags[part] |= SDOPEN; sd->openparts |= (1 << part); - if(scsi_debug & TRACEOPENS) - printf("open %d %d\n",sdstrats,sdqueues); - return(0); -} + SC_DEBUG(sc_link, SDEV_DB3, ("open %d %d\n", sdstrats, sdqueues)); + return 0; -/*******************************************************\ -* Get ownership of a scsi_xfer * -* If need be, sleep on it, until it comes free * -\*******************************************************/ -struct scsi_xfer *sd_get_xs(unit,flags) -int flags; -int unit; -{ - struct scsi_xfer *xs; - int s; - - if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) - { - if (xs = sd_free_xfer[unit]) - { - sd_free_xfer[unit] = xs->next; - xs->flags = 0; - } - } - else - { - s = SPLSD(); - while (!(xs = sd_free_xfer[unit])) - { - sd_xfer_block_wait[unit]++; /* someone waiting! */ - sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1); - sd_xfer_block_wait[unit]--; - } - sd_free_xfer[unit] = xs->next; - splx(s); - xs->flags = 0; +bad: + if (!(sd->openparts)) { + scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT); + sc_link->flags &= ~SDEV_OPEN; } - return(xs); + return errcode; } -/*******************************************************\ -* Free a scsi_xfer, wake processes waiting for it * -\*******************************************************/ -sd_free_xs(unit,xs,flags) -struct scsi_xfer *xs; -int unit; -int flags; +/* + * close the device.. only called if we are the LAST occurence of an open + * device. Convenient now but usually a pain. + */ +errval +sdclose(dev) + dev_t dev; { - int s; - - if(flags & SCSI_NOMASK) - { - if (sd_xfer_block_wait[unit]) - { - printf("doing a wakeup from NOMASK mode\n"); - wakeup((caddr_t)&sd_free_xfer[unit]); - } - xs->next = sd_free_xfer[unit]; - sd_free_xfer[unit] = xs; - } - else - { - s = SPLSD(); - if (sd_xfer_block_wait[unit]) - wakeup((caddr_t)&sd_free_xfer[unit]); - xs->next = sd_free_xfer[unit]; - sd_free_xfer[unit] = xs; - splx(s); - } + unsigned char unit, part; + struct sd_data *sd; + + unit = UNIT(dev); + part = PARTITION(dev); + sd = sd_data[unit]; + sd->partflags[part] &= ~SDOPEN; + sd->openparts &= ~(1 << part); + scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK); + if (!(sd->openparts)) + sd->sc_link->flags &= ~SDEV_OPEN; + return 0; } -/*******************************************************\ -* trim the size of the transfer if needed, * -* called by physio * -* basically the smaller of our max and the scsi driver's* -* minphys (note we have no max) * -\*******************************************************/ -/* Trim buffer length if buffer-size is bigger than page size */ -void sdminphys(bp) -struct buf *bp; +/* + * trim the size of the transfer if needed, called by physio + * basically the smaller of our max and the scsi driver's + * minphys (note we have no max) + * + * Trim buffer length if buffer-size is bigger than page size + */ +void +sdminphys(bp) + struct buf *bp; { - (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); + (*(sd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } -/*******************************************************\ -* Actually translate the requested transfer into * -* one the physical driver can understand * -* The transfer is described by a buf and will include * -* only one physical transfer. * -\*******************************************************/ - -int sdstrategy(bp) -struct buf *bp; +/* + * Actually translate the requested transfer into one the physical driver + * can understand. The transfer is described by a buf and will include + * only one physical transfer. + */ +void +sdstrategy(bp) + struct buf *bp; { - struct buf *dp; - unsigned int opri; - struct sd_data *sd ; - int unit; + struct buf *dp; + u_int32 opri; + struct sd_data *sd; + u_int32 unit; sdstrats++; unit = UNIT((bp->b_dev)); - sd = sd_data + unit; - 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); + sd = sd_data[unit]; + SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy ")); + SC_DEBUG(sd->sc_link, SDEV_DB1, + (" %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno)); sdminphys(bp); - /*******************************************************\ - * If the device has been made invalid, error out * - \*******************************************************/ - if(!(sd->flags & SDVALID)) - { + /* + * If the device has been made invalid, error out + */ + if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) { + sd->flags &= ~SDHAVELABEL; bp->b_error = EIO; goto bad; } - /*******************************************************\ - * "soft" write protect check * - \*******************************************************/ + /* + * "soft" write protect check + */ if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; goto bad; } - /*******************************************************\ - * If it's a null transfer, return immediatly * - \*******************************************************/ - if (bp->b_bcount == 0) - { + /* + * If it's a null transfer, return immediatly + */ + if (bp->b_bcount == 0) { goto done; } - - /*******************************************************\ - * Decide which unit and partition we are talking about * - * only raw is ok if no label * - \*******************************************************/ - if(PARTITION(bp->b_dev) != RAW_PART) - { - if (!(sd->flags & SDHAVELABEL)) - { + /* + * Decide which unit and partition we are talking about + * only raw is ok if no label + */ + if (PARTITION(bp->b_dev) != RAW_PART) { + if (!(sd->flags & SDHAVELABEL)) { bp->b_error = EIO; goto bad; } - /* * do bounds checking, adjust transfer. if error, process. * if end of partition, just return */ - if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0) + if (bounds_check_with_label(bp, &sd->disklabel, sd->wlabel) <= 0) goto done; /* otherwise, process transfer request */ + } else { + bp->b_pblkno = bp->b_blkno; + bp->b_resid = 0; } - opri = SPLSD(); - dp = &sd_buf_queue[unit]; - - /*******************************************************\ - * Place it in the queue of disk activities for this disk* - \*******************************************************/ - disksort(dp, bp); - - /*******************************************************\ - * Tell the device to get going on the transfer if it's * - * not doing anything, otherwise just wait for completion* - \*******************************************************/ + dp = &sd->buf_queue; + + /* + * Use a bounce buffer if necessary + */ +#ifndef NOBOUNCE + if (sd->sc_link->flags & SDEV_BOUNCE) + vm_bounce_alloc(bp); +#endif + + /* + * Place it in the queue of disk activities for this disk + */ + cldisksort(dp, bp, 64*1024); + + /* + * Tell the device to get going on the transfer if it's + * not doing anything, otherwise just wait for completion + */ sdstart(unit); splx(opri); - return; + return /*0*/; bad: bp->b_flags |= B_ERROR; done: - /*******************************************************\ - * Correctly set the buf to indicate a completed xfer * - \*******************************************************/ - bp->b_resid = bp->b_bcount; + /* + * Correctly set the buf to indicate a completed xfer + */ + bp->b_resid = bp->b_bcount; biodone(bp); - return; + return /*0*/; } -/***************************************************************\ -* 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 * -* 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. * -* The bufs are queued by the strategy routine (sdstrategy) * -* * -* This routine is also called after other non-queued requests * -* have been made of the scsi driver, to ensure that the queue * -* continues to be drained. * -* * -* must be called at the correct (highish) spl level * -\***************************************************************/ -/* sdstart() is called at SPLSD from sdstrategy and sd_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 dequeues the buf and creates a scsi command to perform the + * transfer in the buf. The transfer request will call scsi_done + * on completion, which will in turn call this routine again + * so that the next queued transfer is performed. + * The bufs are queued by the strategy routine (sdstrategy) + * + * This routine is also called after other non-queued requests + * have been made of the scsi driver, to ensure that the queue + * continues to be drained. + * + * must be called at the correct (highish) spl level + * sdstart() is called at SPLSD from sdstrategy and scsi_done + */ +void sdstart(unit) -int unit; + u_int32 unit; { - int drivecount; - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_xfer *xs; - struct scsi_rw_big cmd; - int blkno, nblk; - struct sd_data *sd = sd_data + unit; - struct partition *p ; - - if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit); - /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * - \*******************************************************/ - 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 */ - { - return; /* give the special that's waiting a chance to run */ - } + register struct sd_data *sd = sd_data[unit]; + register struct scsi_link *sc_link = sd->sc_link; + struct buf *bp = 0; + struct buf *dp; + struct scsi_rw_big cmd; + u_int32 blkno, nblk; + struct partition *p; + + SC_DEBUG(sc_link, SDEV_DB2, ("sdstart ")); + /* + * Check if the device has room for another command + */ + while (sc_link->opennings) { - - dp = &sd_buf_queue[unit]; - if ((bp = dp->b_actf) != NULL) /* yes, an assign */ - { + /* + * 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 (sc_link->flags & SDEV_WAITING) { + return; + } + /* + * See if there is a buf with work for us to do.. + */ + dp = &sd->buf_queue; + if ((bp = dp->b_actf) == NULL) { /* yes, an assign */ + return; + } dp->b_actf = bp->av_forw; - } - else - { - return; - } - - xs=sd_get_xs(unit,0); /* ok we can grab it */ - xs->flags = INUSE; /* Now ours */ - /*******************************************************\ - * If the device has become invalid, abort all the * - * reads and writes until all files have been closed and * - * re-openned * - \*******************************************************/ - if(!(sd->flags & SDVALID)) - { - xs->error = XS_DRIVER_STUFFUP; - sd_done(unit,xs); /* clean up (calls sdstart) */ - return ; - } - /*******************************************************\ - * We have a buf, now we should move the data into * - * a scsi_xfer definition and try start it * - \*******************************************************/ - /*******************************************************\ - * First, translate the block to absolute * - \*******************************************************/ - p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); - blkno = bp->b_blkno + p->p_offset; - nblk = (bp->b_bcount + 511) >> 9; - - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ - bzero(&cmd, sizeof(cmd)); - cmd.op_code = (bp->b_flags & B_READ) - ? READ_BIG : WRITE_BIG; - cmd.addr_3 = (blkno & 0xff000000) >> 24; - cmd.addr_2 = (blkno & 0xff0000) >> 16; - cmd.addr_1 = (blkno & 0xff00) >> 8; - cmd.addr_0 = blkno & 0xff; - cmd.length2 = (nblk & 0xff00) >> 8; - cmd.length1 = (nblk & 0xff); - /*******************************************************\ - * Fill out the scsi_xfer structure * - * 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) - { - printf("sd%d: oops not queued",unit); - xs->error = XS_DRIVER_STUFFUP; - sd_done(unit,xs); /* clean up (calls sdstart) */ - } - 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; + /* + * If the device has become invalid, abort all the + * reads and writes until all files have been closed and + * re-openned + */ + if (!(sc_link->flags & SDEV_MEDIA_LOADED)) { + sd->flags &= ~SDHAVELABEL; + goto bad; + } + /* + * 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); + blkno = bp->b_blkno + p->p_offset; + nblk = (bp->b_bcount + 511) >> 9; - 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; + /* + * Fill out the scsi command + */ + bzero(&cmd, sizeof(cmd)); + cmd.op_code = (bp->b_flags & B_READ) + ? READ_BIG : WRITE_BIG; + cmd.addr_3 = (blkno & 0xff000000UL) >> 24; + cmd.addr_2 = (blkno & 0xff0000) >> 16; + cmd.addr_1 = (blkno & 0xff00) >> 8; + cmd.addr_0 = blkno & 0xff; + cmd.length2 = (nblk & 0xff00) >> 8; + cmd.length1 = (nblk & 0xff); + /* + * Call the routine that chats with the adapter. + * Note: we cannot sleep as we may be an interrupt + */ + if (scsi_scsi_cmd(sc_link, + (struct scsi_generic *) &cmd, + sizeof(cmd), + (u_char *) bp->b_un.b_addr, + bp->b_bcount, + SD_RETRIES, + 10000, + bp, + SCSI_NOSLEEP | ((bp->b_flags & B_READ) ? + SCSI_DATA_IN : SCSI_DATA_OUT)) + == SUCCESSFULLY_QUEUED) { + sdqueues++; + } else { +bad: + printf("sd%d: oops not queued", unit); 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); + bp->b_flags |= B_ERROR; + biodone(bp); + } } } -/*******************************************************\ -* Perform special action on behalf of the user * -* Knows about the internals of this device * -\*******************************************************/ + +/* + * Perform special action on behalf of the user + * Knows about the internals of this device + */ +errval sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) { - /* struct sd_cmd_buf *args;*/ - int error = 0; - unsigned int opri; + /* struct sd_cmd_buf *args; */ + errval error = 0; unsigned char unit, part; register struct sd_data *sd; - - /*******************************************************\ - * Find the device that the user is talking about * - \*******************************************************/ + /* + * Find the device that the user is talking about + */ unit = UNIT(dev); part = PARTITION(dev); - sd = &sd_data[unit]; - if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit); + sd = sd_data[unit]; + SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd)); - /*******************************************************\ - * If the device is not valid.. abandon ship * - \*******************************************************/ - if (!(sd_data[unit].flags & SDVALID)) - return(EIO); - switch(cmd) - { + /* + * If the device is not valid.. abandon ship + */ + if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) + return (EIO); + switch (cmd) { case DIOCSBAD: - error = EINVAL; + error = EINVAL; break; case DIOCGDINFO: - *(struct disklabel *)addr = sd->disklabel; + *(struct disklabel *) addr = sd->disklabel; + break; + + case DIOCGPART: + ((struct partinfo *) addr)->disklab = &sd->disklabel; + ((struct partinfo *) addr)->part = + &sd->disklabel.d_partitions[PARTITION(dev)]; break; - case DIOCGPART: - ((struct partinfo *)addr)->disklab = &sd->disklabel; - ((struct partinfo *)addr)->part = - &sd->disklabel.d_partitions[PARTITION(dev)]; - break; - - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - error = EBADF; - else - error = setdisklabel(&sd->disklabel, - (struct disklabel *)addr, - /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0, - sd->dosparts); - if (error == 0) { + case DIOCSDINFO: + if ((flag & FWRITE) == 0) + error = EBADF; + else + error = setdisklabel(&sd->disklabel, + (struct disklabel *)addr, + /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */ 0, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts +#endif + ); + if (error == 0) { sd->flags |= SDHAVELABEL; } - break; + break; - case DIOCWLABEL: + case DIOCWLABEL: sd->flags &= ~SDWRITEPROT; - if ((flag & FWRITE) == 0) - error = EBADF; - else - sd->wlabel = *(int *)addr; - break; + if ((flag & FWRITE) == 0) + error = EBADF; + else + sd->wlabel = *(boolean *) addr; + break; - case DIOCWDINFO: + case DIOCWDINFO: sd->flags &= ~SDWRITEPROT; - if ((flag & FWRITE) == 0) - error = EBADF; - else - { - if ((error = setdisklabel(&sd->disklabel - , (struct disklabel *)addr - , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0 - , sd->dosparts)) == 0) - { - int wlab; - - sd->flags |= SDHAVELABEL; /* ok write will succeed */ - - /* simulate opening partition 0 so write succeeds */ - sd->openparts |= (1 << 0); /* XXX */ - wlab = sd->wlabel; - sd->wlabel = 1; - error = writedisklabel(dev, sdstrategy, - &sd->disklabel, sd->dosparts); - sd->wlabel = wlab; - } - } - break; - + if ((flag & FWRITE) == 0) + error = EBADF; + else { + error = setdisklabel(&sd->disklabel, + (struct disklabel *)addr, + /*(sd->flags & SDHAVELABEL) ? sd->openparts : */ 0, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts +#endif + ); + if (!error) { + boolean wlab; + + /* ok - write will succeed */ + sd->flags |= SDHAVELABEL; + + /* simulate opening partition 0 so write succeeds */ + sd->openparts |= (1 << 0); /* XXX */ + wlab = sd->wlabel; + sd->wlabel = 1; + error = writedisklabel(dev, sdstrategy, + &sd->disklabel, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts +#endif + ); + sd->wlabel = wlab; + } + } + break; default: - error = ENOTTY; + if (part == RAW_PART) + error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag); + else + error = ENOTTY; break; } - return (error); + return error; } - -/*******************************************************\ -* Load the label information on the named device * -\*******************************************************/ -int sdgetdisklabel(unit) -unsigned char unit; +/* + * Load the label information on the named device + */ +errval +sdgetdisklabel(unsigned char unit) { - /*unsigned int n, m;*/ - char *errstring; - struct dos_partition *dos_partition_p; - struct sd_data *sd = sd_data + unit; - - /*******************************************************\ - * If the inflo is already loaded, use it * - \*******************************************************/ - if(sd->flags & SDHAVELABEL) return(ESUCCESS); - - bzero(&sd->disklabel,sizeof(struct disklabel)); - /*******************************************************\ - * make partition 3 the whole disk in case of failure * - * then get pdinfo * - \*******************************************************/ + char *errstring; + struct sd_data *sd = sd_data[unit]; + + /* + * If the inflo is already loaded, use it + */ + if (sd->flags & SDHAVELABEL) + return (ESUCCESS); + + bzero(&sd->disklabel, sizeof(struct disklabel)); + /* + * 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; sd->disklabel.d_partitions[RAW_PART].p_offset = 0; sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize; sd->disklabel.d_npartitions = MAXPARTITIONS; - sd->disklabel.d_secsize = 512; /* as long as it's not 0 */ + sd->disklabel.d_secsize = SECSIZE; /* as long as it's not 0 */ sd->disklabel.d_ntracks = sd->params.heads; sd->disklabel.d_nsectors = sd->params.sectors; sd->disklabel.d_ncylinders = sd->params.cyls; sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors; - if (sd->disklabel.d_secpercyl == 0) - { + if (sd->disklabel.d_secpercyl == 0) { sd->disklabel.d_secpercyl = 100; - /* as long as it's not 0 */ - /* readdisklabel divides by it */ + /* as long as it's not 0 - readdisklabel divides by it (?) */ } - - /*******************************************************\ - * all the generic bisklabel extraction routine * - \*******************************************************/ - if(errstring = readdisklabel(makedev(0 ,(unit<disklabel - , sd->dosparts - , 0 - , 0)) - { - printf("sd%d: %s\n",unit, errstring); - return(ENXIO); + /* + * Call the generic disklabel extraction routine + */ + if (errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + 3), + sdstrategy, + &sd->disklabel, +#ifdef NetBSD + &sd->cpudisklabel +#else + sd->dosparts, + 0, + 0 +#endif + )) { + 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); + sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ + return ESUCCESS; } -/*******************************************************\ -* Find out from the device what it's capacity is * -\*******************************************************/ +/* + * Find out from the device what it's capacity is + */ +u_int32 sd_size(unit, flags) + int unit, flags; { struct scsi_read_cap_data rdcap; struct scsi_read_capacity scsi_cmd; - int size; + u_int32 size; - /*******************************************************\ - * make up a scsi command and ask the scsi driver to do * - * it for you. * - \*******************************************************/ + /* + * make up a scsi command and ask the scsi driver to do + * it for you. + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = READ_CAPACITY; - /*******************************************************\ - * If the command works, interpret the result as a 4 byte* - * number of blocks * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &rdcap, - sizeof(rdcap), - 2000, - flags) != 0) - { - printf("could not get size of unit %d\n", unit); - return(0); + /* + * If the command works, interpret the result as a 4 byte + * number of blocks + */ + if (scsi_scsi_cmd(sd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & rdcap, + sizeof(rdcap), + SD_RETRIES, + 2000, + NULL, + flags | SCSI_DATA_IN) != 0) { + printf("sd%d: could not get size\n", unit); + return (0); } else { - size = rdcap.addr_0 + 1 ; + size = rdcap.addr_0 + 1; size += rdcap.addr_1 << 8; size += rdcap.addr_2 << 16; size += rdcap.addr_3 << 24; } - return(size); -} - -/*******************************************************\ -* Get scsi driver to send a "are you ready?" command * -\*******************************************************/ -sd_test_unit_ready(unit,flags) -int unit,flags; -{ - struct scsi_test_unit_ready scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = TEST_UNIT_READY; - - return (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 100000, - flags)); + return (size); } -/*******************************************************\ -* Prevent or allow the user to remove the tape * -\*******************************************************/ -sd_prevent(unit,type,flags) -int unit,type,flags; -{ - struct scsi_prevent scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = PREVENT_ALLOW; - scsi_cmd.prevent=type; - return (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 5000, - flags) ); -} -/*******************************************************\ -* Get scsi driver to send a "start up" command * -\*******************************************************/ -sd_start_unit(unit,flags) -int unit,flags; -{ - struct scsi_start_stop scsi_cmd; - - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = START_STOP; - scsi_cmd.start = 1; - - return (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - 0, - 0, - 2000, - flags)); -} - -/*******************************************************\ -* Tell the device to map out a defective block * -\*******************************************************/ -sd_reassign_blocks(unit,block) +/* + * Tell the device to map out a defective block + */ +errval +sd_reassign_blocks(unit, block) + int unit, block; { - struct scsi_reassign_blocks scsi_cmd; - struct scsi_reassign_blocks_data rbdata; - + struct scsi_reassign_blocks scsi_cmd; + struct scsi_reassign_blocks_data rbdata; bzero(&scsi_cmd, sizeof(scsi_cmd)); bzero(&rbdata, sizeof(rbdata)); @@ -959,508 +792,267 @@ sd_reassign_blocks(unit,block) rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff); rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); - rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff); - - return(sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &rbdata, - sizeof(rbdata), - 5000, - 0)); + rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); + rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff); + + return (scsi_scsi_cmd(sd_data[unit]->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & rbdata, + sizeof(rbdata), + SD_RETRIES, + 5000, + NULL, + SCSI_DATA_OUT)); } - #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) -/*******************************************************\ -* Get the scsi driver to send a full inquiry to the * -* device and use the results to fill out the disk * -* parameter structure. * -\*******************************************************/ - -int sd_get_parms(unit, flags) +/* + * Get the scsi driver to send a full inquiry to the + * device and use the results to fill out the disk + * parameter structure. + */ +errval +sd_get_parms(unit, flags) + int 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 - { - struct scsi_mode_header header; - struct blk_desc blk_desc; - union disk_pages pages; - }scsi_sense; - int sectors; - - /*******************************************************\ - * First check if we have it all loaded * - \*******************************************************/ - if(sd->flags & SDVALID) return(0); - /*******************************************************\ - * First do a mode sense page 3 * - \*******************************************************/ - if (sd_debug) - { - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.page_code = 3; - scsi_cmd.length = 0x24; - /*******************************************************\ - * do the command, but we don't need the results * - * just print them for our interest's sake * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &scsi_sense, - sizeof(scsi_sense), - 2000, - flags) != 0) - { - printf("could not mode sense (3) for unit %d\n", unit); - return(ENXIO); - } - 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), - b2tol(scsi_sense.pages.disk_format.alt_sec), - b2tol(scsi_sense.pages.disk_format.alt_trk_z), - b2tol(scsi_sense.pages.disk_format.alt_trk_v)); - printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n", - b2tol(scsi_sense.pages.disk_format.ph_sec_t), - b2tol(scsi_sense.pages.disk_format.bytes_s), - b2tol(scsi_sense.pages.disk_format.interleave), - sd_size(unit, flags), - _3btol(scsi_sense.blk_desc.blklen)); - } - - - /*******************************************************\ - * do a "mode sense page 4" * - \*******************************************************/ + struct scsi_mode_sense scsi_cmd; + struct scsi_mode_sense_data { + struct scsi_mode_header header; + struct blk_desc blk_desc; + union disk_pages pages; + } scsi_sense; + u_int32 sectors; + + /* + * First check if we have it all loaded + */ + if (sd->sc_link->flags & SDEV_MEDIA_LOADED) + return 0; + + /* + * do a "mode sense page 4" + */ bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = MODE_SENSE; - scsi_cmd.page_code = 4; + scsi_cmd.page = 4; scsi_cmd.length = 0x20; - /*******************************************************\ - * If the command worked, use the results to fill out * - * the parameter structure * - \*******************************************************/ - if (sd_scsi_cmd(unit, - &scsi_cmd, - sizeof(scsi_cmd), - &scsi_sense, - sizeof(scsi_sense), - 2000, - flags) != 0) - { - printf("could not mode sense (4) for unit %d\n", unit); - printf(" using ficticious geometry\n"); - /* use adaptec standard ficticious geometry */ + /* + * If the command worked, use the results to fill out + * the parameter structure + */ + if (scsi_scsi_cmd(sd->sc_link, + (struct scsi_generic *) &scsi_cmd, + sizeof(scsi_cmd), + (u_char *) & scsi_sense, + sizeof(scsi_sense), + SD_RETRIES, + 2000, + NULL, + flags | SCSI_DATA_IN) != 0) { + + printf("sd%d could not mode sense (4).", unit); + printf(" Using ficticious geometry\n"); + /* + * use adaptec standard ficticious geometry + * 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; disk_parms->sectors = 32; - disk_parms->cyls = sectors/(64 * 32); + disk_parms->cyls = sectors / (64 * 32); disk_parms->secsiz = SECSIZE; - } - else - { + disk_parms->disksize = sectors; + } else { - if (sd_debug) - { - printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", + SC_DEBUG(sd->sc_link, SDEV_DB3, + ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2), scsi_sense.pages.rigid_geometry.nheads, b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp), b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), - b2tol(scsi_sense.pages.rigid_geometry.land_zone)); - } + b2tol(scsi_sense.pages.rigid_geometry.land_zone))); - /*******************************************************\ - * KLUDGE!!(for zone recorded disks) * - * give a number of sectors so that sec * trks * cyls * - * is <= disk_size * - \*******************************************************/ + /* + * 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); - disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen); + disk_parms->secsiz = _3btol(scsi_sense.blk_desc.blklen); sectors = sd_size(unit, flags); - sectors /= disk_parms->cyls; - sectors /= disk_parms->heads; - disk_parms->sectors = sectors; /* dubious on SCSI*/ - } - - sd->flags |= SDVALID; - return(0); -} - -/*******************************************************\ -* close the device.. only called if we are the LAST * -* occurence of an open device * -\*******************************************************/ -sdclose(dev) -dev_t dev; -{ - unsigned char unit, part; - unsigned int old_priority; - - 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_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); - } - return(0); -} - -/*******************************************************\ -* ask the scsi driver to perform a command for us. * -* 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. * -* Also tell it where to read/write the data, and how * -* long the data is supposed to be * -\*******************************************************/ -int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) - -int unit,flags; -struct scsi_generic *scsi_cmd; -int cmdlen; -int timeout; -u_char *data_addr; -int datalen; -{ - struct scsi_xfer *xs; - int retval; - int s; - struct sd_data *sd = sd_data + unit; - - if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit); - if(sd->sc_sw) /* If we have a scsi driver */ - { - 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); - - 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: - retval = ESUCCESS; - break; - case TRY_AGAIN_LATER: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - default: - retval = EIO; - } - 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); - } - 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) * -\***************************************************************/ - -int sd_interpret_sense(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct scsi_sense_data *sense; - int key; - int silent; - - /***************************************************************\ - * If the flags say errs are ok, then always return ok. * - \***************************************************************/ - if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); - silent = (xs->flags & SCSI_SILENT); - - sense = &(xs->sense); - switch(sense->error_class) - { - case 7: - { - key=sense->ext.extended.sense_key; - switch(key) - { - case 0x0: - return(ESUCCESS); - case 0x1: - if(!silent) - { - printf("sd%d: soft error(corrected) ", unit); - if(sense->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("\n"); - } - return(ESUCCESS); - case 0x2: - if(!silent)printf("sd%d: not ready\n ", - unit); - return(ENODEV); - case 0x3: - if(!silent) - { - printf("sd%d: medium error ", unit); - if(sense->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("\n"); - } - return(EIO); - case 0x4: - if(!silent)printf("sd%d: non-media hardware failure\n ", - unit); - return(EIO); - case 0x5: - if(!silent)printf("sd%d: illegal request\n ", - unit); - return(EINVAL); - case 0x6: - /***********************************************\ - * If we are not open, then this is not an error * - * as we don't have state yet. Either way, make * - * 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) - { - return(EIO); - } - return(ESUCCESS); /* not an error if nothing's open */ - case 0x7: - if(!silent) - { - printf("sd%d: attempted protection violation ", - unit); - if(sense->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("\n"); - } - return(EACCES); - case 0x8: - if(!silent) - { - printf("sd%d: block wrong state (worm)\n ", - unit); - if(sense->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("\n"); - } - return(EIO); - case 0x9: - if(!silent)printf("sd%d: vendor unique\n", - unit); - return(EIO); - case 0xa: - if(!silent)printf("sd%d: copy aborted\n ", - unit); - return(EIO); - case 0xb: - if(!silent)printf("sd%d: command aborted\n ", - unit); - return(EIO); - case 0xc: - if(!silent) - { - printf("sd%d: search returned\n ", - unit); - if(sense->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("\n"); - } - return(ESUCCESS); - case 0xd: - if(!silent)printf("sd%d: volume overflow\n ", - unit); - return(ENOSPC); - case 0xe: - if(!silent) - { - printf("sd%d: verify miscompare\n ", - unit); - if(sense->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("\n"); - } - return(EIO); - case 0xf: - if(!silent)printf("sd%d: unknown error key\n ", - unit); - return(EIO); + disk_parms->disksize = sectors; + /* Check if none of these values are zero */ + if(disk_parms->heads && disk_parms->cyls) { + sectors /= (disk_parms->heads * disk_parms->cyls); } - break; - } - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - { - if(!silent)printf("sd%d: error class %d code %d\n", - unit, - sense->error_class, - sense->error_code); - if(sense->valid) - if(!silent)printf("block no. %d (decimal)\n", - (sense->ext.unextended.blockhi <<16) - + (sense->ext.unextended.blockmed <<8) - + (sense->ext.unextended.blocklow )); + else { + /* set it to something reasonable */ + disk_parms->heads = 64; + disk_parms->cyls = sectors / (64 * 32); + sectors = 32; } - return(EIO); + /* keep secsiz sane too - we may divide by it later */ + if(disk_parms->secsiz == 0) + disk_parms->secsiz = SECSIZE; + disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */ } + sd->sc_link->flags |= SDEV_MEDIA_LOADED; + return 0; } - - - int sdsize(dev_t dev) { - int unit = UNIT(dev), part = PARTITION(dev), val; + u_int32 unit = UNIT(dev), part = PARTITION(dev), val; struct sd_data *sd; if (unit >= NSD) - return(-1); - - sd = &sd_data[unit]; - 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); - if ( val != 0 || sd->flags & SDWRITEPROT) - return (-1); + return -1; + + 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); + if (val != 0) + return -1; + } + if (sd->flags & SDWRITEPROT) + return -1; - return((int)sd->disklabel.d_partitions[part].p_size); + return (int)sd->disklabel.d_partitions[part].p_size; } -sddump() -{ - printf("sddump() -- not implemented\n"); - return(-1); -} - - +/* + * dump all of physical memory into the partition specified, starting + * at offset 'dumplo' into the partition. + */ +errval +sddump(dev_t dev) +{ /* dump core after a system crash */ + register struct sd_data *sd; /* disk unit to do the IO */ + int32 num; /* number of sectors to write */ + u_int32 unit, part; + int32 blkoff, blknum, blkcnt = MAXTRANSFER; + int32 nblocks; + char *addr; + struct scsi_rw_big cmd; + extern int Maxmem; + static int sddoingadump = 0; + extern caddr_t CADDR1; /* map the page we are about to write, here */ + extern struct pte *CMAP1; + struct scsi_xfer *xs = &sx; + errval retval; + int c; + + addr = (char *) 0; /* starting address */ + + /* toss any characters present prior to dump */ + while ((c = sgetc(1)) && (c != 0x100)); /*syscons and pccons differ */ + + /* size of memory to dump */ + num = Maxmem; + unit = UNIT(dev); /* eventually support floppies? */ + part = PARTITION(dev); /* file system */ + /* check for acceptable drive number */ + if (unit >= NSD) + return (ENXIO); + + sd = sd_data[unit]; + if (!sd) + return (ENXIO); + /* was it ever initialized etc. ? */ + if (!(sd->flags & SDINIT)) + return (ENXIO); + if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED) + return (ENXIO); + if (sd->flags & SDWRITEPROT) + return (ENXIO); + + /* Convert to disk sectors */ + num = (u_int32) num * NBPG / sd->disklabel.d_secsize; + + /* check if controller active */ + if (sddoingadump) + return (EFAULT); + + nblocks = sd->disklabel.d_partitions[part].p_size; + blkoff = sd->disklabel.d_partitions[part].p_offset; + + /* check transfer bounds against partition size */ + if ((dumplo < 0) || ((dumplo + num) > nblocks)) + return (EINVAL); + + sddoingadump = 1; + + blknum = dumplo + blkoff; + while (num > 0) { + *(int *)CMAP1 = + PG_V | PG_KW | trunc_page(addr); + tlbflush(); + /* + * Fill out the scsi command + */ + bzero(&cmd, sizeof(cmd)); + cmd.op_code = WRITE_BIG; + cmd.addr_3 = (blknum & 0xff000000) >> 24; + cmd.addr_2 = (blknum & 0xff0000) >> 16; + cmd.addr_1 = (blknum & 0xff00) >> 8; + cmd.addr_0 = blknum & 0xff; + cmd.length2 = (blkcnt & 0xff00) >> 8; + cmd.length1 = (blkcnt & 0xff); + /* + * Fill out the scsi_xfer structure + * Note: we cannot sleep as we may be an interrupt + * don't use scsi_scsi_cmd() as it may want + * to wait for an xs. + */ + bzero(xs, sizeof(sx)); + xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE; + xs->sc_link = sd->sc_link; + xs->retries = SD_RETRIES; + xs->timeout = 10000; /* 10000 millisecs for a disk ! */ + xs->cmd = (struct scsi_generic *) &cmd; + xs->cmdlen = sizeof(cmd); + xs->resid = blkcnt * 512; + xs->error = XS_NOERROR; + xs->bp = 0; + xs->data = (u_char *) CADDR1; + xs->datalen = blkcnt * 512; + /* + * Pass all this info to the scsi driver. + */ + retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs); + switch (retval) { + case SUCCESSFULLY_QUEUED: + case HAD_ERROR: + return (ENXIO); /* we said not to sleep! */ + case COMPLETE: + break; + default: + return (ENXIO); /* we said not to sleep! */ + } + if ((unsigned) addr % (1024 * 1024) == 0) + printf("%d ", num / 2048); + /* update block count */ + num -= blkcnt; + blknum += blkcnt; + (int) addr += 512 * blkcnt; + /* operator aborting dump? */ + if ((c = sgetc(1)) && (c != 0x100)) + return (EINTR); + } + return (0); +}