Return to BSD News archive
Newsgroups: comp.unix.bsd Path: sserve!manuel!munnari.oz.au!network.ucsd.edu!swrinde!cs.utexas.edu!sun-barr!ames!agate!tfs.com!tfs.com!julian From: julian@tfs.com (Julian Elischer) Subject: New scsi system beta3 (part 3 of 10) Message-ID: <1992Oct3.040129.13586@tfs.com> Organization: TRW Financial Systems Date: Sat, 3 Oct 1992 04:01:29 GMT Lines: 1691 # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # scsi/scsi_disk.h # scsi/sd.c # echo x - scsi/scsi_disk.h sed 's/^X//' >scsi/scsi_disk.h << 'END-of-scsi/scsi_disk.h' X/* X * HISTORY X * $Log: scsi.h,v $ X * X */ X X/* X * SCSI interface description X */ X X/* X * Some lines of this file comes from a file of the name "scsi.h" X * distributed by OSF as part of mach2.5, X * so the following disclaimer has been kept. X * X * Copyright 1990 by Open Software Foundation, X * Grenoble, FRANCE X * X * All Rights Reserved X * X * Permission to use, copy, modify, and distribute this software and X * its documentation for any purpose and without fee is hereby granted, X * provided that the above copyright notice appears in all copies and X * that both the copyright notice and this permission notice appear in X * supporting documentation, and that the name of OSF or Open Software X * Foundation not be used in advertising or publicity pertaining to X * distribution of the software without specific, written prior X * permission. X * X * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, X * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM X * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, X * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION X * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. X */ X X/* X * Largely written by Julian Elischer (julian@tfs.com) X * for TRW Financial Systems. X * X * TRW Financial Systems, in accordance with their agreement with Carnegie X * Mellon University, makes this software available to CMU to distribute X * or use in any manner that they see fit as long as this message is kept with X * the software. For this reason TFS also grants any other persons or X * organisations permission to use or modify this software. X * X * TFS supplies this software to be publicly redistributed X * on the understanding that TFS is not responsible for the correct X * functioning of this software in any circumstances. X * X */ X X/* X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 X */ X X/* X * SCSI command format X */ X X Xstruct scsi_reassign_blocks X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[3]; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_rw X{ X u_char op_code; X u_char addr_2:5; /* Most significant */ X u_char lun:3; X u_char addr_1; X u_char addr_0; /* least significant */ X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_rw_big X{ X u_char op_code; X u_char rel_addr:1; X u_char :4; /* Most significant */ X u_char lun:3; X u_char addr_3; X u_char addr_2; X u_char addr_1; X u_char addr_0; /* least significant */ X u_char reserved;; X u_char length2; X u_char length1; X u_char link:1; X u_char flag:1; X u_char :4; X u_char vendor:2; X}; X Xstruct scsi_read_capacity X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char addr_3; /* Most Significant */ X u_char addr_2; X u_char addr_1; X u_char addr_0; /* Least Significant */ X u_char unused[3]; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_start_stop X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[2]; X u_char start:1; X u_char loej:1; X u_char :6; X u_char link:1; X u_char flag:1; X u_char :6; X}; X X X X/* X * Opcodes X */ X X#define REASSIGN_BLOCKS 0x07 X#define READ_COMMAND 0x08 X#define WRITE_COMMAND 0x0a X#define MODE_SELECT 0x15 X#define MODE_SENSE 0x1a X#define START_STOP 0x1b X#define PREVENT_ALLOW 0x1e X#define READ_CAPACITY 0x25 X#define READ_BIG 0x28 X#define WRITE_BIG 0x2a X X X Xstruct scsi_read_cap_data X{ X u_char addr_3; /* Most significant */ X u_char addr_2; X u_char addr_1; X u_char addr_0; /* Least significant */ X u_char length_3; /* Most significant */ X u_char length_2; X u_char length_1; X u_char length_0; /* Least significant */ X}; X Xstruct scsi_reassign_blocks_data X{ X u_char reserved[2]; X u_char length_msb; X u_char length_lsb; X struct X { X u_char dlbaddr_3; /* defect logical block address (MSB) */ X u_char dlbaddr_2; X u_char dlbaddr_1; X u_char dlbaddr_0; /* defect logical block address (LSB) */ X } defect_descriptor[1]; X}; X Xunion disk_pages /* this is the structure copied from osf */ X{ X struct page_disk_format { X u_char pg_code:6; /* page code (should be 3) */ X u_char :2; X u_char pg_length; /* page length (should be 0x16) */ X u_char trk_z_1; /* tracks per zone (MSB) */ X u_char trk_z_0; /* tracks per zone (LSB) */ X u_char alt_sec_1; /* alternate sectors per zone (MSB) */ X u_char alt_sec_0; /* alternate sectors per zone (LSB) */ X u_char alt_trk_z_1; /* alternate tracks per zone (MSB) */ X u_char alt_trk_z_0; /* alternate tracks per zone (LSB) */ X u_char alt_trk_v_1; /* alternate tracks per volume (MSB) */ X u_char alt_trk_v_0; /* alternate tracks per volume (LSB) */ X u_char ph_sec_t_1; /* physical sectors per track (MSB) */ X u_char ph_sec_t_0; /* physical sectors per track (LSB) */ X u_char bytes_s_1; /* bytes per sector (MSB) */ X u_char bytes_s_0; /* bytes per sector (LSB) */ X u_char interleave_1;/* interleave (MSB) */ X u_char interleave_0;/* interleave (LSB) */ X u_char trk_skew_1; /* track skew factor (MSB) */ X u_char trk_skew_0; /* track skew factor (LSB) */ X u_char cyl_skew_1; /* cylinder skew (MSB) */ X u_char cyl_skew_0; /* cylinder skew (LSB) */ X u_char reserved1:4; X u_char surf:1; X u_char rmb:1; X u_char hsec:1; X u_char ssec:1; X u_char reserved2; X u_char reserved3; X } disk_format; X struct page_rigid_geometry { X u_char pg_code:7; /* page code (should be 4) */ X u_char mbone:1; /* must be one */ X u_char pg_length; /* page length (should be 0x16) */ X u_char ncyl_2; /* number of cylinders (MSB) */ X u_char ncyl_1; /* number of cylinders */ X u_char ncyl_0; /* number of cylinders (LSB) */ X u_char nheads; /* number of heads */ X u_char st_cyl_wp_2; /* starting cyl., write precomp (MSB) */ X u_char st_cyl_wp_1; /* starting cyl., write precomp */ X u_char st_cyl_wp_0; /* starting cyl., write precomp (LSB) */ X u_char st_cyl_rwc_2;/* starting cyl., red. write cur (MSB)*/ X u_char st_cyl_rwc_1;/* starting cyl., red. write cur */ X u_char st_cyl_rwc_0;/* starting cyl., red. write cur (LSB)*/ X u_char driv_step_1; /* drive step rate (MSB) */ X u_char driv_step_0; /* drive step rate (LSB) */ X u_char land_zone_2; /* landing zone cylinder (MSB) */ X u_char land_zone_1; /* landing zone cylinder */ X u_char land_zone_0; /* landing zone cylinder (LSB) */ X u_char reserved1; X u_char reserved2; X u_char reserved3; X } rigid_geometry; X} ; END-of-scsi/scsi_disk.h echo x - scsi/sd.c sed 's/^X//' >scsi/sd.c << 'END-of-scsi/sd.c' X/* X * Written by Julian Elischer (julian@tfs.com) X * for TRW Financial Systems for use under the MACH(2.5) operating system. X * X * TRW Financial Systems, in accordance with their agreement with Carnegie X * Mellon University, makes this software available to CMU to distribute X * or use in any manner that they see fit as long as this message is kept with X * the software. For this reason TFS also grants any other persons or X * organisations permission to use or modify this software. X * X * TFS supplies this software to be publicly redistributed X * on the understanding that TFS is not responsible for the correct X * functioning of this software in any circumstances. X * X */ X X/* X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 X */ X X/* RCS header and log section X * $Log: $ X */ X#define SPLSD splbio X#define ESUCCESS 0 X#include <sd.h> X#include <sys/types.h> X#include <sys/param.h> X#include <sys/dkbad.h> X#include <sys/systm.h> X#include <sys/conf.h> X#include <sys/file.h> X#include <sys/stat.h> X#include <sys/ioctl.h> X#include <sys/buf.h> X#include <sys/uio.h> X#include <sys/malloc.h> X#include <sys/errno.h> X#include <sys/disklabel.h> X#include <scsi/scsi_all.h> X#include <scsi/scsi_disk.h> X#include <scsi/scsiconf.h> X Xlong int sdstrats,sdqueues; X X X#include <ddb.h> X#if NDDB > 0 Xint Debugger(); X#else NDDB > 0 X#define Debugger() X#endif NDDB > 0 X X X#define PAGESIZ 4096 X#define SECSIZE 512 X#define PDLOCATION 29 X#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff) X#define SDOUTSTANDING 2 X#define SDQSIZE 4 X#define SD_RETRIES 4 X X#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part))) X#define UNITSHIFT 3 X#define PARTITION(z) (minor(z) & 0x07) X#define RAW_PART 3 X#define UNIT(z) ( (minor(z) >> UNITSHIFT) ) X X#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART ) X Xstruct buf sd_buf_queue[NSD]; Xint sd_done(); Xint sdstrategy(); X Xint sd_debug = 0; X Xstruct scsi_xfer *sd_free_xfer[NSD]; Xint sd_xfer_block_wait[NSD]; X Xstruct sd_data X{ X int flags; X#define SDVALID 0x02 /* PARAMS LOADED */ X#define SDINIT 0x04 /* device has been init'd */ X#define SDWAIT 0x08 /* device has someone waiting */ X#define SDHAVELABEL 0x10 /* have read the label */ X#define SDDOSPART 0x20 /* Have read the DOS partition table */ X#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/ X struct scsi_switch *sc_sw; /* address of scsi low level switch */ X int ctlr; /* so they know which one we want */ X int targ; /* our scsi target ID */ X int lu; /* out scsi lu */ X long int ad_info; /* info about the adapter */ X int cmdscount; /* cmds allowed outstanding by board*/ X int wlabel; /* label is writable */ X struct disk_parms X { X u_char heads; /* Number of heads */ X u_short cyls; /* Number of cylinders */ X u_char sectors;/*dubious*/ /* Number of sectors/track */ X u_short secsiz; /* Number of bytes/sector */ X u_long disksize; /* total number sectors */ X }params; X struct disklabel disklabel; X struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */ X int partflags[MAXPARTITIONS]; /* per partition flags */ X#define SDOPEN 0x01 X int openparts; /* one bit for each open partition */ X unsigned int sd_start_of_unix; /* unix vs dos partitions */ X}sd_data[NSD]; X X Xstatic int next_sd_unit = 0; X/***********************************************************************\ X* The routine called by the low level scsi routine when it discovers * X* A device suitable for this driver * X\***********************************************************************/ X Xint sdattach(ctlr,targ,lu,scsi_switch) Xstruct scsi_switch *scsi_switch; X{ X int unit,i; X unsigned char *tbl; X struct sd_data *sd; X struct disk_parms *dp; X long int ad_info; X struct scsi_xfer *sd_scsi_xfer; X X unit = next_sd_unit++; X sd = sd_data + unit; X dp = &(sd->params); X if(scsi_debug & PRINTROUTINES) printf("sdattach: "); X /*******************************************************\ X * Check we have the resources for another drive * X \*******************************************************/ X if( unit >= NSD) X { X printf("Too many scsi disks..(%d > %d) reconfigure kernel",(unit + 1),NSD); X return(0); X } X /*******************************************************\ X * Store information needed to contact our base driver * X \*******************************************************/ X sd->sc_sw = scsi_switch; X sd->ctlr = ctlr; X sd->targ = targ; X sd->lu = lu; X if(sd->sc_sw->adapter_info) X { X sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr)); X sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS; X if(sd->cmdscount > SDOUTSTANDING) X { X sd->cmdscount = SDOUTSTANDING; X } X } X else X { X sd->ad_info = 1; X sd->cmdscount = 1; X } X X i = sd->cmdscount; X sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i X ,M_TEMP, M_NOWAIT); X while(i-- ) X { X sd_scsi_xfer->next = sd_free_xfer[unit]; X sd_free_xfer[unit] = sd_scsi_xfer; X sd_scsi_xfer++; X } X /*******************************************************\ X * Use the subdriver to request information regarding * X * the drive. We cannot use interrupts yet, so the * X * request must specify this. * X \*******************************************************/ X sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK); X printf(" sd%d: %dMB, cyls %d, heads %d, secs %d, bytes/sec %d\n", X unit, X ( dp->cyls X * dp->heads X * dp->sectors X * dp->secsiz X ) X / (1024 * 1024), X dp->cyls, X dp->heads, X dp->sectors, X dp->secsiz); X /*******************************************************\ X * Set up the bufs for this device * X \*******************************************************/ X sd->flags |= SDINIT; X return; X X} X X X X/*******************************************************\ X* open the device. Make sure the partition info * X* is a up-to-date as can be. * X\*******************************************************/ Xsdopen(dev) X{ X int errcode = 0; X int unit, part; X struct disk_parms disk_parms; X struct sd_data *sd ; X X unit = UNIT(dev); X part = PARTITION(dev); X sd = sd_data + unit; X if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) X printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" X , dev, unit, NSD, part); X /*******************************************************\ X * Check the unit is legal * X \*******************************************************/ X if ( unit >= NSD ) X { X return(ENXIO); X } X /*******************************************************\ X * Make sure the disk has been initialised * X * At some point in the future, get the scsi driver * X * to look for a new device if we are not initted * X \*******************************************************/ X if (! (sd->flags & SDINIT)) X { X return(ENXIO); X } X X /*******************************************************\ X * If it's been invalidated, and not everybody has * X * closed it then forbid re-entry. * X \*******************************************************/ X if ((! (sd->flags & SDVALID)) X && ( sd->openparts)) X return(ENXIO); X /*******************************************************\ X * Check that it is still responding and ok. * X * "unit attention errors should occur here if the drive * X * has been restarted or the pack changed * X \*******************************************************/ X X if(scsi_debug & TRACEOPENS) X printf("device is "); X if (sd_test_unit_ready(unit,0)) X { X if(scsi_debug & TRACEOPENS) printf("not reponding\n"); X return(ENXIO); X } X if(scsi_debug & TRACEOPENS) X printf("ok\n"); X /*******************************************************\ X * In case it is a funny one, tell it to start * X * not needed for most hard drives (ignore failure) * X \*******************************************************/ X sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT); X if(scsi_debug & TRACEOPENS) X printf("started "); X /*******************************************************\ X * Load the physical device parameters * X \*******************************************************/ X sd_get_parms(unit, 0); /* sets SDVALID */ X if (sd->params.secsiz != SECSIZE) X { X printf("sd%d: Can't deal with %d bytes logical blocks\n" X ,unit, sd->params.secsiz); X Debugger(); X return(ENXIO); X } X if(scsi_debug & TRACEOPENS) X printf("Params loaded "); X /*******************************************************\ X * Load the partition info if not already loaded * X \*******************************************************/ X sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ X if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) X { X sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ X return(errcode); X } X if(scsi_debug & TRACEOPENS) X printf("Disklabel loaded "); X /*******************************************************\ X * Check the partition is legal * X \*******************************************************/ X if ( part >= MAXPARTITIONS ) { X sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ X return(ENXIO); X } X if(scsi_debug & TRACEOPENS) X printf("ok"); X /*******************************************************\ X * Check that the partition exists * X \*******************************************************/ X if (( sd->disklabel.d_partitions[part].p_fstype == FS_UNUSED ) X && (part != RAW_PART)) X { X sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ X return(ENXIO); X } X sd->partflags[part] |= SDOPEN; X sd->openparts |= (1 << part); X if(scsi_debug & TRACEOPENS) X printf("open %d %d\n",sdstrats,sdqueues); X return(0); X} X X/*******************************************************\ X* Get ownership of a scsi_xfer * X* If need be, sleep on it, until it comes free * X\*******************************************************/ Xstruct scsi_xfer *sd_get_xs(unit,flags) Xint flags; Xint unit; X{ X struct scsi_xfer *xs; X int s; X X if(flags & (SCSI_NOSLEEP | SCSI_NOMASK)) X { X if (xs = sd_free_xfer[unit]) X { X sd_free_xfer[unit] = xs->next; X xs->flags = 0; X } X } X else X { X s = SPLSD(); X while (!(xs = sd_free_xfer[unit])) X { X sd_xfer_block_wait[unit]++; /* someone waiting! */ X sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1); X sd_xfer_block_wait[unit]--; X } X sd_free_xfer[unit] = xs->next; X splx(s); X xs->flags = 0; X } X return(xs); X} X X/*******************************************************\ X* Free a scsi_xfer, wake processes waiting for it * X\*******************************************************/ Xsd_free_xs(unit,xs,flags) Xstruct scsi_xfer *xs; Xint unit; Xint flags; X{ X int s; X X if(flags & SCSI_NOMASK) X { X if (sd_xfer_block_wait[unit]) X { X printf("doing a wakeup from NOMASK mode\n"); X wakeup((caddr_t)&sd_free_xfer[unit]); X } X xs->next = sd_free_xfer[unit]; X sd_free_xfer[unit] = xs; X } X else X { X s = SPLSD(); X if (sd_xfer_block_wait[unit]) X wakeup((caddr_t)&sd_free_xfer[unit]); X xs->next = sd_free_xfer[unit]; X sd_free_xfer[unit] = xs; X splx(s); X } X} X X/*******************************************************\ X* trim the size of the transfer if needed, * X* called by physio * X* basically the smaller of our max and the scsi driver's* X* minphys (note we have no max) * X\*******************************************************/ X/* Trim buffer length if buffer-size is bigger than page size */ Xvoid sdminphys(bp) Xstruct buf *bp; X{ X (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); X} X X/*******************************************************\ X* Actually translate the requested transfer into * X* one the physical driver can understand * X* The transfer is described by a buf and will include * X* only one physical transfer. * X\*******************************************************/ X Xint sdstrategy(bp) Xstruct buf *bp; X{ X struct buf *dp; X unsigned int opri; X struct sd_data *sd ; X int unit; X X sdstrats++; X unit = UNIT((bp->b_dev)); X sd = sd_data + unit; X if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy "); X if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n", X unit,bp->b_bcount,bp->b_blkno); X sdminphys(bp); X /*******************************************************\ X * If the device has been made invalid, error out * X \*******************************************************/ X if(!(sd->flags & SDVALID)) X { X bp->b_error = EIO; X goto bad; X } X /*******************************************************\ X * "soft" write protect check * X \*******************************************************/ X if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) { X bp->b_error = EROFS; X goto bad; X } X /*******************************************************\ X * If it's a null transfer, return immediatly * X \*******************************************************/ X if (bp->b_bcount == 0) X { X goto done; X } X X /*******************************************************\ X * Decide which unit and partition we are talking about * X * only raw is ok if no label * X \*******************************************************/ X if(PARTITION(bp->b_dev) != RAW_PART) X { X if (!(sd->flags & SDHAVELABEL)) X { X bp->b_error = EIO; X goto bad; X } X X /* X * do bounds checking, adjust transfer. if error, process. X * if end of partition, just return X */ X if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0) X goto done; X /* otherwise, process transfer request */ X } X X opri = SPLSD(); X dp = &sd_buf_queue[unit]; X X /*******************************************************\ X * Place it in the queue of disk activities for this disk* X \*******************************************************/ X disksort(dp, bp); X X /*******************************************************\ X * Tell the device to get going on the transfer if it's * X * not doing anything, otherwise just wait for completion* X \*******************************************************/ X sdstart(unit); X X splx(opri); X return; Xbad: X bp->b_flags |= B_ERROR; Xdone: X X /*******************************************************\ X * Correctly set the buf to indicate a completed xfer * X \*******************************************************/ X bp->b_resid = bp->b_bcount; X biodone(bp); X return; X} X X/***************************************************************\ X* sdstart looks to see if there is a buf waiting for the device * X* and that the device is not already busy. If both are true, * X* It deques the buf and creates a scsi command to perform the * X* transfer in the buf. The transfer request will call sd_done * X* on completion, which will in turn call this routine again * X* so that the next queued transfer is performed. * X* The bufs are queued by the strategy routine (sdstrategy) * X* * X* This routine is also called after other non-queued requests * X* have been made of the scsi driver, to ensure that the queue * X* continues to be drained. * X* * X* must be called at the correct (highish) spl level * X\***************************************************************/ X/* sdstart() is called at SPLSD from sdstrategy and sd_done*/ Xsdstart(unit) Xint unit; X{ X int drivecount; X register struct buf *bp = 0; X register struct buf *dp; X struct scsi_xfer *xs; X struct scsi_rw_big cmd; X int blkno, nblk; X struct sd_data *sd = sd_data + unit; X struct partition *p ; X X if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit); X /*******************************************************\ X * See if there is a buf to do and we are not already * X * doing one * X \*******************************************************/ X if(!sd_free_xfer[unit]) X { X return; /* none for us, unit already underway */ X } X X if(sd_xfer_block_wait[unit]) /* there is one, but a special waits */ X { X return; /* give the special that's waiting a chance to run */ X } X X X dp = &sd_buf_queue[unit]; X if ((bp = dp->b_actf) != NULL) /* yes, an assign */ X { X dp->b_actf = bp->av_forw; X } X else X { X return; X } X X xs=sd_get_xs(unit,0); /* ok we can grab it */ X xs->flags = INUSE; /* Now ours */ X /*******************************************************\ X * If the device has become invalid, abort all the * X * reads and writes until all files have been closed and * X * re-openned * X \*******************************************************/ X if(!(sd->flags & SDVALID)) X { X xs->error = XS_DRIVER_STUFFUP; X sd_done(unit,xs); /* clean up (calls sdstart) */ X return ; X } X /*******************************************************\ X * We have a buf, now we should move the data into * X * a scsi_xfer definition and try start it * X \*******************************************************/ X /*******************************************************\ X * First, translate the block to absolute * X \*******************************************************/ X p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); X blkno = bp->b_blkno + p->p_offset; X nblk = (bp->b_bcount + 511) >> 9; X X /*******************************************************\ X * Fill out the scsi command * X \*******************************************************/ X bzero(&cmd, sizeof(cmd)); X cmd.op_code = (bp->b_flags & B_READ) X ? READ_BIG : WRITE_BIG; X cmd.addr_3 = (blkno & 0xff000000) >> 24; X cmd.addr_2 = (blkno & 0xff0000) >> 16; X cmd.addr_1 = (blkno & 0xff00) >> 8; X cmd.addr_0 = blkno & 0xff; X cmd.length2 = (nblk & 0xff00) >> 8; X cmd.length1 = (nblk & 0xff); X /*******************************************************\ X * Fill out the scsi_xfer structure * X * Note: we cannot sleep as we may be an interrupt * X \*******************************************************/ X xs->flags |= SCSI_NOSLEEP; X xs->adapter = sd->ctlr; X xs->targ = sd->targ; X xs->lu = sd->lu; X xs->retries = SD_RETRIES; X xs->timeout = 10000;/* 10000 millisecs for a disk !*/ X xs->cmd = (struct scsi_generic *)&cmd; X xs->cmdlen = sizeof(cmd); X xs->resid = bp->b_bcount; X xs->when_done = sd_done; X xs->done_arg = unit; X xs->done_arg2 = (int)xs; X xs->error = XS_NOERROR; X xs->bp = bp; X xs->data = (u_char *)bp->b_un.b_addr; X xs->datalen = bp->b_bcount; X /*******************************************************\ X * Pass all this info to the scsi driver. * X \*******************************************************/ X X X X if ( (*(sd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) X { X printf("sd%d: oops not queued",unit); X xs->error = XS_DRIVER_STUFFUP; X sd_done(unit,xs); /* clean up (calls sdstart) */ X } X sdqueues++; X} X X/*******************************************************\ X* This routine is called by the scsi interrupt when * X* the transfer is complete. X\*******************************************************/ Xint sd_done(unit,xs) Xint unit; Xstruct scsi_xfer *xs; X{ X struct buf *bp; X int retval; X int retries = 0; X X if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); X if (! (xs->flags & INUSE)) X panic("scsi_xfer not in use!"); X if(bp = xs->bp) X { X switch(xs->error) X { X case XS_NOERROR: X bp->b_error = 0; X bp->b_resid = 0; X break; X X case XS_SENSE: X retval = (sd_interpret_sense(unit,xs)); X if(retval) X { X bp->b_flags |= B_ERROR; X bp->b_error = retval; X } X break; X X case XS_TIMEOUT: X printf("sd%d timeout\n",unit); X X case XS_BUSY: /* should retry */ /* how? */ X /************************************************/ X /* SHOULD put buf back at head of queue */ X /* and decrement retry count in (*xs) */ X /* HOWEVER, this should work as a kludge */ X /************************************************/ X if(xs->retries--) X { X xs->error = XS_NOERROR; X xs->flags &= ~ITSDONE; X if ( (*(sd_data[unit].sc_sw->scsi_cmd))(xs) X == SUCCESSFULLY_QUEUED) X { /* don't wake the job, ok? */ X return; X } X xs->flags |= ITSDONE; X } /* fall through */ X X case XS_DRIVER_STUFFUP: X bp->b_flags |= B_ERROR; X bp->b_error = EIO; X break; X default: X printf("sd%d: unknown error category from scsi driver\n" X ,unit); X } X biodone(bp); X sd_free_xs(unit,xs,0); X sdstart(unit); /* If there's anything waiting.. do it */ X } X else /* special has finished */ X { X wakeup(xs); X } X} X/*******************************************************\ X* Perform special action on behalf of the user * X* Knows about the internals of this device * X\*******************************************************/ Xsdioctl(dev_t dev, int cmd, caddr_t addr, int flag) X{ X /* struct sd_cmd_buf *args;*/ X int error = 0; X unsigned int opri; X unsigned char unit, part; X register struct sd_data *sd; X X X /*******************************************************\ X * Find the device that the user is talking about * X \*******************************************************/ X unit = UNIT(dev); X part = PARTITION(dev); X sd = &sd_data[unit]; X if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit); X X /*******************************************************\ X * If the device is not valid.. abandon ship * X \*******************************************************/ X if (!(sd_data[unit].flags & SDVALID)) X return(EIO); X switch(cmd) X { X X case DIOCSBAD: X error = EINVAL; X break; X X case DIOCGDINFO: X *(struct disklabel *)addr = sd->disklabel; X break; X X case DIOCGPART: X ((struct partinfo *)addr)->disklab = &sd->disklabel; X ((struct partinfo *)addr)->part = X &sd->disklabel.d_partitions[PARTITION(dev)]; X break; X X case DIOCSDINFO: X if ((flag & FWRITE) == 0) X error = EBADF; X else X error = setdisklabel(&sd->disklabel, X (struct disklabel *)addr, X /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0, X sd->dosparts); X if (error == 0) { X sd->flags |= SDHAVELABEL; X } X break; X X case DIOCWLABEL: X sd->flags &= ~SDWRITEPROT; X if ((flag & FWRITE) == 0) X error = EBADF; X else X sd->wlabel = *(int *)addr; X break; X X case DIOCWDINFO: X sd->flags &= ~SDWRITEPROT; X if ((flag & FWRITE) == 0) X error = EBADF; X else X { X if ((error = setdisklabel(&sd->disklabel X , (struct disklabel *)addr X , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0 X , sd->dosparts)) == 0) X { X int wlab; X X sd->flags |= SDHAVELABEL; /* ok write will succeed */ X X /* simulate opening partition 0 so write succeeds */ X sd->openparts |= (1 << 0); /* XXX */ X wlab = sd->wlabel; X sd->wlabel = 1; X error = writedisklabel(dev, sdstrategy, X &sd->disklabel, sd->dosparts); X sd->wlabel = wlab; X } X } X break; X X X default: X error = ENOTTY; X break; X } X return (error); X} X X X/*******************************************************\ X* Load the label information on the named device * X\*******************************************************/ Xint sdgetdisklabel(unit) Xunsigned char unit; X{ X /*unsigned int n, m;*/ X char *errstring; X struct dos_partition *dos_partition_p; X struct sd_data *sd = sd_data + unit; X X /*******************************************************\ X * If the inflo is already loaded, use it * X \*******************************************************/ X if(sd->flags & SDHAVELABEL) return; X X bzero(&sd->disklabel,sizeof(struct disklabel)); X /*******************************************************\ X * make partition 3 the whole disk in case of failure * X * then get pdinfo * X \*******************************************************/ X sd->disklabel.d_partitions[RAW_PART].p_offset = 0; X sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize; X sd->disklabel.d_npartitions = MAXPARTITIONS; X sd->disklabel.d_secsize = 512; /* as long as it's not 0 */ X sd->disklabel.d_secpercyl = 100; /* as long as it's not 0 */ X /* readdisklabel divides by it */ X X /*******************************************************\ X * all the generic bisklabel extraction routine * X \*******************************************************/ X if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3) X , sdstrategy X , &sd->disklabel X , sd->dosparts X , 0 X , 0)) X { X printf("sd%d: %s\n",unit, errstring); X return(ENXIO); X } X /*******************************************************\ X * leave partition 2 "open" for raw I/O * X \*******************************************************/ X X sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ X return(ESUCCESS); X} X X/*******************************************************\ X* Find out from the device what it's capacity is * X\*******************************************************/ Xsd_size(unit, flags) X{ X struct scsi_read_cap_data rdcap; X struct scsi_read_capacity scsi_cmd; X int size; X X /*******************************************************\ X * make up a scsi command and ask the scsi driver to do * X * it for you. * X \*******************************************************/ X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = READ_CAPACITY; X X /*******************************************************\ X * If the command works, interpret the result as a 4 byte* X * number of blocks * X \*******************************************************/ X if (sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X &rdcap, X sizeof(rdcap), X 2000, X flags) != 0) X { X printf("could not get size of unit %d\n", unit); X return(0); X } else { X size = rdcap.addr_0 + 1 ; X size += rdcap.addr_1 << 8; X size += rdcap.addr_2 << 16; X size += rdcap.addr_3 << 24; X } X return(size); X} X X/*******************************************************\ X* Get scsi driver to send a "are you ready?" command * X\*******************************************************/ Xsd_test_unit_ready(unit,flags) Xint unit,flags; X{ X struct scsi_test_unit_ready scsi_cmd; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = TEST_UNIT_READY; X X return (sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X 0, X 0, X 100000, X flags)); X} X X/*******************************************************\ X* Prevent or allow the user to remove the tape * X\*******************************************************/ Xsd_prevent(unit,type,flags) Xint unit,type,flags; X{ X struct scsi_prevent scsi_cmd; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = PREVENT_ALLOW; X scsi_cmd.prevent=type; X return (sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X 0, X 0, X 5000, X flags) ); X} X/*******************************************************\ X* Get scsi driver to send a "start up" command * X\*******************************************************/ Xsd_start_unit(unit,flags) Xint unit,flags; X{ X struct scsi_start_stop scsi_cmd; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = START_STOP; X scsi_cmd.start = 1; X X return (sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X 0, X 0, X 2000, X flags)); X} X X/*******************************************************\ X* Tell the device to map out a defective block * X\*******************************************************/ Xsd_reassign_blocks(unit,block) X{ X struct scsi_reassign_blocks scsi_cmd; X struct scsi_reassign_blocks_data rbdata; X X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X bzero(&rbdata, sizeof(rbdata)); X scsi_cmd.op_code = REASSIGN_BLOCKS; X X rbdata.length_msb = 0; X rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]); X rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff); X rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff); X rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff); X rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff); X X return(sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X &rbdata, X sizeof(rbdata), X 5000, X 0)); X} X X#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) X X/*******************************************************\ X* Get the scsi driver to send a full inquiry to the * X* device and use the results to fill out the disk * X* parameter structure. * X\*******************************************************/ X Xint sd_get_parms(unit, flags) X{ X struct sd_data *sd = sd_data + unit; X struct disk_parms *disk_parms = &sd->params; X struct scsi_mode_sense scsi_cmd; X struct scsi_mode_sense_data X { X struct scsi_mode_header header; X struct blk_desc blk_desc; X union disk_pages pages; X }scsi_sense; X int sectors; X X /*******************************************************\ X * First check if we have it all loaded * X \*******************************************************/ X if(sd->flags & SDVALID) return(0); X /*******************************************************\ X * First do a mode sense page 3 * X \*******************************************************/ X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = MODE_SENSE; X scsi_cmd.page_code = 3; X scsi_cmd.length = 0x24; X /*******************************************************\ X * do the command, but we don't need the results * X * just print them for our interest's sake * X \*******************************************************/ X if (sd_debug) X { X if (sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X &scsi_sense, X sizeof(scsi_sense), X 2000, X flags) != 0) X { X printf("could not mode sense (3) for unit %d\n", unit); X return(ENXIO); X } X printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n", X unit, X b2tol(scsi_sense.pages.disk_format.trk_z), X b2tol(scsi_sense.pages.disk_format.alt_sec), X b2tol(scsi_sense.pages.disk_format.alt_trk_z), X b2tol(scsi_sense.pages.disk_format.alt_trk_v)); X printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n", X b2tol(scsi_sense.pages.disk_format.ph_sec_t), X b2tol(scsi_sense.pages.disk_format.bytes_s), X b2tol(scsi_sense.pages.disk_format.interleave), X sd_size(unit, flags), X _3btol(scsi_sense.blk_desc.blklen)); X } X X X /*******************************************************\ X * do a "mode sense page 4" * X \*******************************************************/ X bzero(&scsi_cmd, sizeof(scsi_cmd)); X scsi_cmd.op_code = MODE_SENSE; X scsi_cmd.page_code = 4; X scsi_cmd.length = 0x20; X /*******************************************************\ X * If the command worked, use the results to fill out * X * the parameter structure * X \*******************************************************/ X if (sd_scsi_cmd(unit, X &scsi_cmd, X sizeof(scsi_cmd), X &scsi_sense, X sizeof(scsi_sense), X 2000, X flags) != 0) X { X printf("could not mode sense (4) for unit %d\n", unit); X return(ENXIO); X } X X if (sd_debug) X printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", X _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2), X scsi_sense.pages.rigid_geometry.nheads, X b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp), X b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), X b2tol(scsi_sense.pages.rigid_geometry.land_zone)); X X /*******************************************************\ X * give a number of sectors so that sec * trks * cyls * X * is <= disk_size * X \*******************************************************/ X disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads; X disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2); X disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen); X X sectors = sd_size(unit, flags) * disk_parms->secsiz; X sectors /= SECSIZE; X sectors /= disk_parms->cyls; X sectors /= disk_parms->heads; X disk_parms->sectors = sectors; /* dubious on SCSI*/ X disk_parms->secsiz = SECSIZE; X X sd->flags |= SDVALID; X return(0); X} X X/*******************************************************\ X* close the device.. only called if we are the LAST * X* occurence of an open device * X\*******************************************************/ Xsdclose(dev) Xdev_t dev; X{ X unsigned char unit, part; X unsigned int old_priority; X X unit = UNIT(dev); X part = PARTITION(dev); X sd_data[unit].partflags[part] &= ~SDOPEN; X sd_data[unit].openparts &= ~(1 << part); X if(sd_data[unit].openparts == 0) /* if all partitions closed */ X { X sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); X } X return(0); X} X X/*******************************************************\ X* ask the scsi driver to perform a command for us. * X* Call it through the switch table, and tell it which * X* sub-unit we want, and what target and lu we wish to * X* talk to. Also tell it where to find the command * X* how long int is. * X* Also tell it where to read/write the data, and how * X* long the data is supposed to be * X\*******************************************************/ Xint sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) X Xint unit,flags; Xstruct scsi_generic *scsi_cmd; Xint cmdlen; Xint timeout; Xu_char *data_addr; Xint datalen; X{ X struct scsi_xfer *xs; X int retval; X int s; X struct sd_data *sd = sd_data + unit; X X if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit); X if(sd->sc_sw) /* If we have a scsi driver */ X { X xs = sd_get_xs(unit,flags); /* should wait unless booting */ X if(!xs) X { X printf("sd_scsi_cmd%d: controller busy" X " (this should never happen)\n",unit); X return(EBUSY); X } X xs->flags |= INUSE; X /*******************************************************\ X * Fill out the scsi_xfer structure * X \*******************************************************/ X xs->flags |= flags; X xs->adapter = sd->ctlr; X xs->targ = sd->targ; X xs->lu = sd->lu; X xs->retries = SD_RETRIES; X xs->timeout = timeout; X xs->cmd = scsi_cmd; X xs->cmdlen = cmdlen; X xs->data = data_addr; X xs->datalen = datalen; X xs->resid = datalen; X xs->when_done = (flags & SCSI_NOMASK) X ?(int (*)())0 X :sd_done; X xs->done_arg = unit; X xs->done_arg2 = (int)xs; Xretry: xs->error = XS_NOERROR; X xs->bp = 0; X retval = (*(sd->sc_sw->scsi_cmd))(xs); X switch(retval) X { X case SUCCESSFULLY_QUEUED: X while(!(xs->flags & ITSDONE)) X sleep(xs,PRIBIO+1); X X case HAD_ERROR: X /*printf("err = %d ",xs->error);*/ X switch(xs->error) X { X case XS_NOERROR: X retval = ESUCCESS; X break; X case XS_SENSE: X retval = (sd_interpret_sense(unit,xs)); X break; X case XS_DRIVER_STUFFUP: X retval = EIO; X break; X case XS_TIMEOUT: X if(xs->retries-- ) X { X xs->flags &= ~ITSDONE; X goto retry; X } X retval = EIO; X break; X case XS_BUSY: X if(xs->retries-- ) X { X xs->flags &= ~ITSDONE; X goto retry; X } X retval = EIO; X break; X default: X retval = EIO; X printf("sd%d: unknown error category from scsi driver\n" X ,unit); X } X break; X case COMPLETE: X retval = ESUCCESS; X break; X case TRY_AGAIN_LATER: X if(xs->retries-- ) X { X xs->flags &= ~ITSDONE; X goto retry; X } X retval = EIO; X break; X default: X retval = EIO; X } X sd_free_xs(unit,xs,flags); X sdstart(unit); /* check if anything is waiting fr the xs */ X } X else X { X printf("sd%d: not set up\n",unit); X return(EINVAL); X } X return(retval); X} X/***************************************************************\ X* Look at the returned sense and act on the error and detirmine * X* The unix error number to pass back... (0 = report no error) * X\***************************************************************/ X Xint sd_interpret_sense(unit,xs) Xint unit; Xstruct scsi_xfer *xs; X{ X struct scsi_sense_data *sense; X int key; X int silent; X X /***************************************************************\ X * If the flags say errs are ok, then always return ok. * X \***************************************************************/ X if (xs->flags & SCSI_ERR_OK) return(ESUCCESS); X silent = (xs->flags & SCSI_SILENT); X X sense = &(xs->sense); X switch(sense->error_class) X { X case 7: X { X key=sense->ext.extended.sense_key; X switch(key) X { X case 0x0: X return(ESUCCESS); X case 0x1: X if(!silent) X { X printf("sd%d: soft error(corrected) ", unit); X if(sense->valid) X { X printf("block no. %d (decimal)", X (sense->ext.extended.info[0] <<24), X (sense->ext.extended.info[1] <<16), X (sense->ext.extended.info[2] <<8), X (sense->ext.extended.info[3] )); X } X printf("\n"); X } X return(ESUCCESS); X case 0x2: X if(!silent)printf("sd%d: not ready\n ", X unit); X return(ENODEV); X case 0x3: X if(!silent) X { X printf("sd%d: medium error ", unit); X if(sense->valid) X { X printf("block no. %d (decimal)", X (sense->ext.extended.info[0] <<24), X (sense->ext.extended.info[1] <<16), X (sense->ext.extended.info[2] <<8), X (sense->ext.extended.info[3] )); X } X printf("\n"); X } X return(EIO); X case 0x4: X if(!silent)printf("sd%d: non-media hardware failure\n ", X unit); X return(EIO); X case 0x5: X if(!silent)printf("sd%d: illegal request\n ", X unit); X return(EINVAL); X case 0x6: X /***********************************************\ X * If we are not open, then this is not an error * X * as we don't have state yet. Either way, make * X * sure that we don't have any residual state * X \***********************************************/ X if(!silent)printf("sd%d: Unit attention.\n ", unit); X sd_data[unit].flags &= ~(SDVALID | SDHAVELABEL); X if (sd_data[unit].openparts) X { X return(EIO); X } X return(ESUCCESS); /* not an error if nothing's open */ X case 0x7: X if(!silent) X { X printf("sd%d: attempted protection violation ", X unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24), X (sense->ext.extended.info[1] <<16), X (sense->ext.extended.info[2] <<8), X (sense->ext.extended.info[3] )); X } X printf("\n"); X } X return(EACCES); X case 0x8: X if(!silent) X { X printf("sd%d: block wrong state (worm)\n ", X unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24), X (sense->ext.extended.info[1] <<16), X (sense->ext.extended.info[2] <<8), X (sense->ext.extended.info[3] )); X } X printf("\n"); X } X return(EIO); X case 0x9: X if(!silent)printf("sd%d: vendor unique\n", X unit); X return(EIO); X case 0xa: X if(!silent)printf("sd%d: copy aborted\n ", X unit); X return(EIO); X case 0xb: X if(!silent)printf("sd%d: command aborted\n ", X unit); X return(EIO); X case 0xc: X if(!silent) X { X printf("sd%d: search returned\n ", X unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24), X (sense->ext.extended.info[1] <<16), X (sense->ext.extended.info[2] <<8), X (sense->ext.extended.info[3] )); X } X printf("\n"); X } X return(ESUCCESS); X case 0xd: X if(!silent)printf("sd%d: volume overflow\n ", X unit); X return(ENOSPC); X case 0xe: X if(!silent) X { X printf("sd%d: verify miscompare\n ", X unit); X if(sense->valid) X { X printf("block no. %d (decimal)\n", X (sense->ext.extended.info[0] <<24), X (sense->ext.extended.info[1] <<16), X (sense->ext.extended.info[2] <<8), X (sense->ext.extended.info[3] )); X } X printf("\n"); X } X return(EIO); X case 0xf: X if(!silent)printf("sd%d: unknown error key\n ", X unit); X return(EIO); X } X break; X } X case 0: X case 1: X case 2: X case 3: X case 4: X case 5: X case 6: X { X if(!silent)printf("sd%d: error class %d code %d\n", X unit, X sense->error_class, X sense->error_code); X if(sense->valid) X if(!silent)printf("block no. %d (decimal)\n", X (sense->ext.unextended.blockhi <<16), X + (sense->ext.unextended.blockmed <<8), X + (sense->ext.unextended.blocklow )); X } X return(EIO); X } X} X X X X Xint Xsdsize(dev_t dev) X{ X int unit = UNIT(dev), part = PARTITION(dev), val; X struct sd_data *sd; X X if (unit >= NSD) X return(-1); X X sd = &sd_data[unit]; X if((sd->flags & SDINIT) == 0) return(-1); X if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) X val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0); X if ( val != 0 || sd->flags & SDWRITEPROT) X return (-1); X X return((int)sd->disklabel.d_partitions[part].p_size); X} X Xsddump() X{ X printf("sddump() -- not implemented\n"); X return(-1); X} X X X X X END-of-scsi/sd.c exit