diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1993-08-28 03:08:59 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1993-08-28 03:08:59 +0000 |
commit | bb7686bc5d8502daf5555b4de12d8a81926fb13a (patch) | |
tree | 96b769956a4e8f8c1e7b98ca459e2817ea02e56a /sys | |
parent | f4f821656d5e9b5c905d1efd765f180be84a7e56 (diff) | |
download | FreeBSD-src-bb7686bc5d8502daf5555b4de12d8a81926fb13a.zip FreeBSD-src-bb7686bc5d8502daf5555b4de12d8a81926fb13a.tar.gz |
Revised drivers from Julian. Support for generic scsi. Fixed scsi tape (st.c)
problems with respect to multiple tar files on one tape. Now uses malloc
of data structures to reduce static kernel size.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/scsi/README | 45 | ||||
-rw-r--r-- | sys/scsi/cd.c | 52 | ||||
-rw-r--r-- | sys/scsi/scsi_generic.h | 61 | ||||
-rw-r--r-- | sys/scsi/scsi_tape.h | 11 | ||||
-rw-r--r-- | sys/scsi/scsiconf.c | 19 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 27 | ||||
-rw-r--r-- | sys/scsi/sd.c | 664 | ||||
-rw-r--r-- | sys/scsi/st.c | 2065 |
8 files changed, 1668 insertions, 1276 deletions
diff --git a/sys/scsi/README b/sys/scsi/README index dfeeb17..5fd8e09 100644 --- a/sys/scsi/README +++ b/sys/scsi/README @@ -13,9 +13,14 @@ scsi/scsi_all.h scsi/scsi_disk.h scsi/sd.c +sys/mtio.h (modified) scsi/scsi_tape.h scsi/st.c +sys/sgio.h +scsi/scsi_generic.h +scsi/sg.c /* port not complete */ + sys/chio.h scsi/scsi_changer.h scsi/ch.c @@ -52,15 +57,16 @@ AEG Character recognition devices * Calera Character recognition devices * Kodak IL900 scanner * Exabyte tape changer device. +GENERIC SCSI DEVICES (user generated scsi commands) (port not complete) ---------------------------------------------------------------- There are also working bottom end drivers for: ---------------------------------------------------------------- adaptec 1542 (and 1742 in 1542 mode) -bustec 742a +bustec 742a (apparently works for VESA version) adaptec 174x -Ultrastore 14f +Ultrastore 14f (works for 34f (VESA version)) ---------------------------------------------------------------- @@ -90,6 +96,12 @@ e.g. the first tape found will become st0 (minor number 0) These devices could be on the same scsi bus or different scsi busses. That would not change their minor numbers. +THE EXCEPTION TO THIS IS IN THE GENERIC SCSI DRIVER. in which case +the following mapping applies: + +BB LLL TTT B= scsi bus number, T = target number, L = LUN. +(yes I know it's strange but it's SGI compatible) + It is possible to run two different TYPES of scsi adapters at the same time and have st0 on one and st1 on another. (for example) @@ -122,6 +134,7 @@ encoded into the minor number in some way, and this may be supported at some timein the future, using minor numbers greater than 128. (or maybe a different major number) + I will also be writing (probably) a generic scsi-error handling routine that will be table driven, so that the routine can be removed from each individual driver. With enough care, @@ -145,16 +158,17 @@ scsi-changer.h commands medium changer devices --- CHAPTER 16 ---------ioctl definitions------------- User accessable structures (e.g. ioctl definitions) have been -placed in sys/cdio and sys/chio (based after sys/mtio for +placed in sys/cdio, sys/sgio and sys/chio (based after sys/mtio for the ioctls for mag tapes (including st). -----------cd-rom----------------- The cd rom driver ha been tested by a number of people and grefen@wilbur.zdv.uni-mainz.de has completed the audio play functions. -He tells me he has some Public Domain package that -allows an control of the cd player from an Xwindow -but I don't have it. +(xcdplayer was available from the 'from_ref' directory on agate) + +At this time it is possible audio play is broken on cdroms and I will +be unable to fix it until I get one to test. -------------media changer--------------- Once again courtesy of grefen@wilbur.zdv.uni-mainz.de. @@ -163,6 +177,8 @@ If anyone has an exabyte tape changer or similar, contact the author for information regarding the control interface and program. +WARNING: This has not been tested for a LONG TIME! + -----------booting from an AHA-174x--------- For some reason I have not yet worked out, the BIOS-based bootblocks I have posted will not boot @@ -173,3 +189,20 @@ mode during probe, so it can be left in standard mode during the boot. During the next reboot, the bios will place it back in standard mode ready for the NEXT boot. +[Update: This has apparently been fixed in the newest NetBSD/FreeBSD +releases ] + + + +---------recent changes----------- +Removed all bitfields from machine independent sections to make +it possible for them to be used on big-endian architectures. + +Removed scsi specific timeouts in favour of system timeout handling. + +Many structures (getting more all the time) now dynamically allocated. + +Addition of code in the tape driver to recognise models of drive that +have particular problems so they can be handled specially. + +many bug-fixes and cleanups. diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index d387c04..628845d 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id$ + * $Id: cd.c,v 1.6 93/08/26 21:09:07 julian Exp Locker: julian $ */ #define SPLCD splbio @@ -115,8 +115,6 @@ struct scsi_switch *scsi_switch; struct cd_parms *dp; unit = next_cd_unit++; - cd = cd_data + unit; - dp = &(cd->params); if(scsi_debug & PRINTROUTINES) printf("cdattach: "); /*******************************************************\ * Check we have the resources for another drive * @@ -127,6 +125,8 @@ struct scsi_switch *scsi_switch; (unit + 1),NCD); return(0); } + cd = cd_data + unit; + dp = &(cd->params); /*******************************************************\ * Store information needed to contact our base driver * \*******************************************************/ @@ -713,6 +713,27 @@ cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) )); } break; + case CDIOCPLAYMSF: + { + struct ioc_play_msf *args + = (struct ioc_play_msf *)addr; + struct cd_mode_data data; + if(error = cd_get_mode(unit,&data,AUDIO_PAGE)) + break; + data.page.audio.flags &= ~CD_PA_SOTC; + data.page.audio.flags |= CD_PA_IMMED; + if(error = cd_set_mode(unit,&data)) + break; + return(cd_play_msf(unit + ,args->start_m + ,args->start_s + ,args->start_f + ,args->end_m + ,args->end_s + ,args->end_f + )); + } + break; case CDIOCPLAYBLOCKS: { struct ioc_play_blocks *args @@ -1182,6 +1203,31 @@ int unit,strack,sindex,etrack,eindex; return(retval); } /*******************************************************\ +* Get scsi driver to send a "play msf" command * +\*******************************************************/ +cd_play_msf(unit,startm,starts,startf,endm,ends,endf) +int unit,startm,starts,startf,endm,ends,endf; +{ + struct scsi_play_msf scsi_cmd; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = PLAY_MSF; + scsi_cmd.start_m=startm; + scsi_cmd.start_s=starts; + scsi_cmd.start_f=startf; + scsi_cmd.end_m=endm; + scsi_cmd.end_s=ends; + scsi_cmd.end_f=endf; + + return (cd_scsi_cmd(unit, + &scsi_cmd, + sizeof(scsi_cmd), + 0, + 0, + 2000, + 0)); +} +/*******************************************************\ * Get scsi driver to send a "start up" command * \*******************************************************/ cd_pause(unit,go) diff --git a/sys/scsi/scsi_generic.h b/sys/scsi/scsi_generic.h new file mode 100644 index 0000000..338aa51 --- /dev/null +++ b/sys/scsi/scsi_generic.h @@ -0,0 +1,61 @@ +#ifndef _SCSI_GENERIC_H_ +#define _SCSI_GENERIC_H_ + +/* + * Contributed by HD Associates (hd@world.std.com). + * Copyright (c) 1992, 1993 HD Associates + * + * Berkeley style copyright. I've just snarfed it out of stdio.h: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* generic SCSI header file. We use the same minor number format + * as on SGI except that the flag bits aren't available because they + * are used as the board index. + * + * The minor number format is: + * FF UUU III (FFUU UIII) + * + * Where: + * FF is the board index + * UUU are the LUN + * III is the SCSI ID (controller) + */ + +#define G_SCSI_FLAG(DEV) (((DEV) & 0xC0) >> 6) +#define G_SCSI_UNIT(DEV) G_SCSI_FLAG(DEV) +#define G_SCSI_LUN(DEV) (((DEV) & 0x38) >> 3) +#define G_SCSI_ID(DEV) ((DEV) & 0x7) + +#define G_SCSI_MINOR(FLAG, LUN, ID) \ + (((FLAG) << 6) | ((LUN) << 3) | (ID)) + +#endif /* _SCSI_GENERIC_H_ */ diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h index 96d14a6..74e656c 100644 --- a/sys/scsi/scsi_tape.h +++ b/sys/scsi/scsi_tape.h @@ -16,15 +16,21 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * + */ + +/* * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id$ + * $Id: scsi_tape.h,v 1.7 93/08/26 21:09:32 julian Exp Locker: julian $ */ + + /* - * SCSI command format + * SCSI command formats */ + struct scsi_rw_tape { u_char op_code; @@ -183,6 +189,7 @@ struct blk_desc_cipher #define HALFINCH_800 0x01 #define HALFINCH_1600 0x02 #define HALFINCH_6250 0x03 +#define QIC_11 0x04 /* from Archive 150S Theory of Op. XXX */ #define QIC_24 0x05 /* may be bad, works for CIPHER ST150S XXX */ #define QIC_120 0x0f #define QIC_150 0x10 diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c index f701805..e15cc9a 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id$ + * $Id: scsiconf.c,v 1.6 93/08/26 21:09:39 julian Exp Locker: julian $ */ #include <sys/types.h> @@ -22,6 +22,7 @@ #include "sd.h" #include "ch.h" #include "cd.h" +#include "sg.h" #ifdef MACH #include <i386/machparam.h> @@ -231,12 +232,12 @@ struct scsi_switch *scsi_switch; } targ++; } -#if NGENSCSI > 0 +#if NSG > 0 /***************************************************************\ * If available hook up the generic scsi driver, letting it * * know which target is US. (i.e. illegal or at least special) * \***************************************************************/ - genscsi_attach(unit,scsi_addr,0,scsi_switch); + sg_attach(unit,scsi_addr,scsi_switch); #endif scsibus++; /* next time we are on the NEXT scsi bus */ } @@ -449,7 +450,7 @@ int *maybe_more; strncpy(model,"unknown",16); strncpy(version,"????",4); } - printf("%s%d targ %d lun %d: type %d(%s) %s <%s%s%s> SCSI%d\n" + printf("%s%d targ %d lun %d: type %d(%s) %s SCSI%d\n" ,scsi_switch->name ,unit ,target @@ -457,14 +458,20 @@ int *maybe_more; ,type ,dtype ,remov?"removable":"fixed" + ,inqbuf.version & SID_ANSII + ); + printf("%s%d targ %d lun %d: <%s%s%s>\n" + ,scsi_switch->name + ,unit + ,target + ,lu ,manu ,model ,version - ,inqbuf.version & SID_ANSII ); if(qtype[0]) { - printf("%s%d targ %d lun %d: qulaifier %d(%s)\n" + printf("%s%d targ %d lun %d: qualifier %d(%s)\n" ,scsi_switch->name ,unit ,target diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index 004787e..b0b45ef 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id$ + * $Id: scsiconf.h,v 1.3 93/08/26 21:09:43 julian Exp Locker: julian $ */ /***********************************************\ @@ -24,18 +24,18 @@ \***********************************************/ struct scsi_switch { - char *name; /* name of scsi bus controller */ int (*scsi_cmd)(); void (*scsi_minphys)(); int (*open_target_lu)(); int (*close_target_lu)(); long int (*adapter_info)(); /* see definitions below */ - u_long spare[3]; + char *name; /* name of scsi bus controller */ + u_long spare[2]; }; #define AD_INF_MAX_CMDS 0x000000FF /* maximum number of entries queuable to a device by the adapter */ -/* 24 bits of other adapter charcteristics go here */ +/* 24 bits of other adapter characteristics go here */ /***********************************************\ * The scsi debug control bits * @@ -57,6 +57,7 @@ extern int scsi_debug; #define TRY_AGAIN_LATER 1 #define COMPLETE 2 #define HAD_ERROR 3 +#define ESCAPE_NOT_SUPPORTED 4 struct scsi_xfer { @@ -78,6 +79,13 @@ struct scsi_xfer int error; struct buf *bp; struct scsi_sense_data sense; + + /* Believe it or not, Some targets fall on the ground with + * anything but a certain sense length. + */ + int req_sense_length; /* Explicit request sense length */ + + int status; /* SCSI status */ }; /********************************/ /* Flag values */ @@ -94,6 +102,17 @@ struct scsi_xfer #define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */ #define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */ #define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */ +#define SCSI_ESCAPE 0x2000 /* Escape operation */ + +/*************************************************************************/ +/* Escape op codes. This provides an extensible setup for operations */ +/* that are not scsi commands. They are intended for modal operations. */ +/*************************************************************************/ + +#define SCSI_OP_TARGET 0x0001 +#define SCSI_OP_RESET 0x0002 +#define SCSI_OP_BDINFO 0x0003 + /********************************/ /* Error values */ /********************************/ diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 15d229b..d24f28b 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,5 +1,5 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Written by Julian Elischer (julian@dialix.oz.au) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -12,9 +12,9 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 + * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - * $Id$ + * $Id: sd.c,v 1.10 93/08/26 21:09:44 julian Exp Locker: julian $ */ #define SPLSD splbio @@ -68,7 +68,9 @@ struct buf sd_buf_queue[NSD]; int sd_done(); int sdstrategy(); +#ifdef SDDEBUG int sd_debug = 0; +#endif /*SDDEBUG*/ struct scsi_xfer *sd_free_xfer[NSD]; int sd_xfer_block_wait[NSD]; @@ -103,7 +105,7 @@ struct sd_data #define SDOPEN 0x01 int openparts; /* one bit for each open partition */ unsigned int sd_start_of_unix; /* unix vs dos partitions */ -}sd_data[NSD]; +}*sd_data[NSD]; static int next_sd_unit = 0; @@ -123,9 +125,9 @@ struct scsi_switch *scsi_switch; struct scsi_xfer *sd_scsi_xfer; unit = next_sd_unit++; - sd = sd_data + unit; - dp = &(sd->params); +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("sdattach: "); +#endif /*SDDEBUG*/ /*******************************************************\ * Check we have the resources for another drive * \*******************************************************/ @@ -134,6 +136,18 @@ struct scsi_switch *scsi_switch; printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",(unit + 1),NSD); return(0); } + if(sd_data[unit]) + { + printf("sd%d: unit already has storage allocated!\n",unit); + return(0); + } + sd = sd_data[unit] = malloc(sizeof(struct sd_data),M_DEVBUF,M_NOWAIT); + if(!sd) + { + printf("malloc failed in sd.c\n"); + return(0); + } + dp = &(sd->params); /*******************************************************\ * Store information needed to contact our base driver * \*******************************************************/ @@ -179,9 +193,6 @@ struct scsi_switch *scsi_switch; dp->heads, dp->sectors, dp->secsiz); - /*******************************************************\ - * Set up the bufs for this device * - \*******************************************************/ sd->flags |= SDINIT; return; @@ -202,10 +213,12 @@ sdopen(dev) unit = UNIT(dev); part = PARTITION(dev); - sd = sd_data + unit; + sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n" , dev, unit, NSD, part); +#endif /*SDDEBUG*/ /*******************************************************\ * Check the unit is legal * \*******************************************************/ @@ -231,51 +244,64 @@ sdopen(dev) && ( sd->openparts)) return(ENXIO); /*******************************************************\ - * Check that it is still responding and ok. * - * "unit attention errors should occur here if the drive * - * has been restarted or the pack changed * + * "unit attention" errors should occur here if the * + * drive has been restarted or the pack changed. * + * just ingnore the result, it's a decoy instruction * + * The error code will act on the error though * + * and invalidate any media information we had. * \*******************************************************/ + sd_test_unit_ready(unit,0); - if(scsi_debug & TRACEOPENS) - printf("device is "); - if (sd_test_unit_ready(unit,0)) - { - if(scsi_debug & TRACEOPENS) printf("not reponding\n"); - return(ENXIO); - } - if(scsi_debug & TRACEOPENS) - printf("ok\n"); /*******************************************************\ * In case it is a funny one, tell it to start * * not needed for most hard drives (ignore failure) * \*******************************************************/ sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT); + + /*******************************************************\ + * Check that it is still responding and ok. * + \*******************************************************/ + if (sd_test_unit_ready(unit,0)) + { +#ifdef SDDEBUG + if(scsi_debug & TRACEOPENS) printf("device not reponding\n"); +#endif /*SDDEBUG*/ + return(ENXIO); + } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) - printf("started "); + printf("device ok\n"); +#endif /*SDDEBUG*/ + /*******************************************************\ * Load the physical device parameters * \*******************************************************/ sd_get_parms(unit, 0); /* sets SDVALID */ - if (sd->params.secsiz != SECSIZE) + if (sd->params.secsiz != SECSIZE) /* XXX One day...*/ { printf("sd%d: Can't deal with %d bytes logical blocks\n" ,unit, sd->params.secsiz); Debugger(); return(ENXIO); } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("Params loaded "); +#endif /*SDDEBUG*/ /*******************************************************\ * Load the partition info if not already loaded * + * Lock the pack in * \*******************************************************/ - sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) { - sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ + sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); return(errcode); } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("Disklabel loaded "); +#endif /*SDDEBUG*/ /*******************************************************\ * Check the partition is legal * \*******************************************************/ @@ -283,8 +309,10 @@ sdopen(dev) sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */ return(ENXIO); } +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("ok"); +#endif /*SDDEBUG*/ /*******************************************************\ * Check that the partition exists * \*******************************************************/ @@ -296,8 +324,10 @@ sdopen(dev) } sd->partflags[part] |= SDOPEN; sd->openparts |= (1 << part); +#ifdef SDDEBUG if(scsi_debug & TRACEOPENS) printf("open %d %d\n",sdstrats,sdqueues); +#endif /*SDDEBUG*/ return(0); } @@ -377,7 +407,7 @@ int flags; void sdminphys(bp) struct buf *bp; { - (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); + (*(sd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); } /*******************************************************\ @@ -397,10 +427,12 @@ struct buf *bp; sdstrats++; unit = UNIT((bp->b_dev)); - sd = sd_data + unit; + sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy "); if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n", unit,bp->b_bcount,bp->b_blkno); +#endif /*SDDEBUG*/ sdminphys(bp); /*******************************************************\ * If the device has been made invalid, error out * @@ -477,7 +509,7 @@ done: /***************************************************************\ * sdstart looks to see if there is a buf waiting for the device * * and that the device is not already busy. If both are true, * -* It deques the buf and creates a scsi command to perform the * +* It dequeues the buf and creates a scsi command to perform the * * transfer in the buf. The transfer request will call sd_done * * on completion, which will in turn call this routine again * * so that the next queued transfer is performed. * @@ -499,37 +531,41 @@ int unit; struct scsi_xfer *xs; struct scsi_rw_big cmd; int blkno, nblk; - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; struct partition *p ; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit); +#endif /*SDDEBUG*/ /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * + * Check if the device is already running full capacity * \*******************************************************/ if(!sd_free_xfer[unit]) { return; /* none for us, unit already underway */ } - if(sd_xfer_block_wait[unit]) /* there is one, but a special waits */ + /*******************************************************\ + * there is excess capacity, but a special waits * + * It'll need the adapter as soon as we clear out of the * + * way and let it run (user level wait). * + \*******************************************************/ + if(sd_xfer_block_wait[unit]) { - return; /* give the special that's waiting a chance to run */ + return; } - + /*******************************************************\ + * See if there is a buf with work for us to do.. * + \*******************************************************/ dp = &sd_buf_queue[unit]; - if ((bp = dp->b_actf) != NULL) /* yes, an assign */ + if ((bp = dp->b_actf) == NULL) /* yes, an assign */ { - dp->b_actf = bp->av_forw; - } - else - { return; } - xs=sd_get_xs(unit,0); /* ok we can grab it */ - xs->flags = INUSE; /* Now ours */ + dp->b_actf = bp->av_forw; + /*******************************************************\ * If the device has become invalid, abort all the * * reads and writes until all files have been closed and * @@ -537,15 +573,12 @@ int unit; \*******************************************************/ if(!(sd->flags & SDVALID)) { - xs->error = XS_DRIVER_STUFFUP; - sd_done(unit,xs); /* clean up (calls sdstart) */ - return ; + goto bad; } /*******************************************************\ - * We have a buf, now we should move the data into * - * a scsi_xfer definition and try start it * - \*******************************************************/ - /*******************************************************\ + * We have a buf, now we know we are going to go through * + * With this thing.. * + * * * First, translate the block to absolute * \*******************************************************/ p = sd->disklabel.d_partitions + PARTITION(bp->b_dev); @@ -565,112 +598,31 @@ int unit; cmd.length2 = (nblk & 0xff00) >> 8; cmd.length1 = (nblk & 0xff); /*******************************************************\ - * Fill out the scsi_xfer structure * + * Call the routine that chats with the adapter * * Note: we cannot sleep as we may be an interrupt * \*******************************************************/ - xs->flags |= SCSI_NOSLEEP; - xs->adapter = sd->ctlr; - xs->targ = sd->targ; - xs->lu = sd->lu; - xs->retries = SD_RETRIES; - xs->timeout = 10000;/* 10000 millisecs for a disk !*/ - xs->cmd = (struct scsi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->resid = bp->b_bcount; - xs->when_done = sd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->error = XS_NOERROR; - xs->bp = bp; - xs->data = (u_char *)bp->b_un.b_addr; - xs->datalen = bp->b_bcount; - /*******************************************************\ - * Pass all this info to the scsi driver. * - \*******************************************************/ - - - - if ( (*(sd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) + if (sd_scsi_cmd(unit, + &cmd, + sizeof(cmd), + (u_char *)bp->b_un.b_addr, + bp->b_bcount, + 10000, + bp, + SCSI_NOSLEEP| ((bp->b_flags & B_READ)? + SCSI_DATA_IN : SCSI_DATA_OUT)) + != SUCCESSFULLY_QUEUED) { +bad: printf("sd%d: oops not queued",unit); - xs->error = XS_DRIVER_STUFFUP; - sd_done(unit,xs); /* clean up (calls sdstart) */ + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return ; } sdqueues++; } /*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int sd_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - int retries = 0; - - if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); - if (! (xs->flags & INUSE)) - panic("scsi_xfer not in use!"); - if(bp = xs->bp) - { - switch(xs->error) - { - case XS_NOERROR: - bp->b_error = 0; - bp->b_resid = 0; - break; - - case XS_SENSE: - retval = (sd_interpret_sense(unit,xs)); - if(retval) - { - bp->b_flags |= B_ERROR; - bp->b_error = retval; - } - break; - - case XS_TIMEOUT: - printf("sd%d timeout\n",unit); - - case XS_BUSY: /* should retry */ /* how? */ - /************************************************/ - /* SHOULD put buf back at head of queue */ - /* and decrement retry count in (*xs) */ - /* HOWEVER, this should work as a kludge */ - /************************************************/ - if(xs->retries--) - { - xs->error = XS_NOERROR; - xs->flags &= ~ITSDONE; - if ( (*(sd_data[unit].sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* don't wake the job, ok? */ - return; - } - xs->flags |= ITSDONE; - } /* fall through */ - - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("sd%d: unknown error category from scsi driver\n" - ,unit); - } - biodone(bp); - sd_free_xs(unit,xs,0); - sdstart(unit); /* If there's anything waiting.. do it */ - } - else /* special has finished */ - { - wakeup(xs); - } -} -/*******************************************************\ * Perform special action on behalf of the user * * Knows about the internals of this device * \*******************************************************/ @@ -688,13 +640,15 @@ sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) \*******************************************************/ unit = UNIT(dev); part = PARTITION(dev); - sd = &sd_data[unit]; + sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit); +#endif /*SDDEBUG*/ /*******************************************************\ * If the device is not valid.. abandon ship * \*******************************************************/ - if (!(sd_data[unit].flags & SDVALID)) + if (!(sd->flags & SDVALID)) return(EIO); switch(cmd) { @@ -778,7 +732,7 @@ unsigned char unit; /*unsigned int n, m;*/ char *errstring; struct dos_partition *dos_partition_p; - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; /*******************************************************\ * If the inflo is already loaded, use it * @@ -789,6 +743,7 @@ unsigned char unit; /*******************************************************\ * make partition 3 the whole disk in case of failure * * then get pdinfo * + * for historical reasons, make part a same as raw part * \*******************************************************/ sd->disklabel.d_partitions[0].p_offset = 0; sd->disklabel.d_partitions[0].p_size = sd->params.disksize; @@ -804,11 +759,11 @@ unsigned char unit; { sd->disklabel.d_secpercyl = 100; /* as long as it's not 0 */ - /* readdisklabel divides by it */ + /* readdisklabel divides by it (?)*/ } /*******************************************************\ - * all the generic disklabel extraction routine * + * Call the generic disklabel extraction routine * \*******************************************************/ if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3) , sdstrategy @@ -820,9 +775,6 @@ unsigned char unit; printf("sd%d: %s\n",unit, errstring); return(ENXIO); } - /*******************************************************\ - * leave partition 2 "open" for raw I/O * - \*******************************************************/ sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */ return(ESUCCESS); @@ -854,7 +806,8 @@ sd_size(unit, flags) &rdcap, sizeof(rdcap), 2000, - flags) != 0) + NULL, + flags | SCSI_DATA_IN) != 0) { printf("sd0%: could not get size\n", unit); return(0); @@ -884,17 +837,21 @@ int unit,flags; 0, 0, 100000, + NULL, flags)); } /*******************************************************\ * Prevent or allow the user to remove the tape * +* Don't change this status if any partitions are open * \*******************************************************/ sd_prevent(unit,type,flags) int unit,type,flags; { struct scsi_prevent scsi_cmd; + if(sd_data[unit]->openparts) return; + bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PREVENT_ALLOW; scsi_cmd.how=type; @@ -904,6 +861,7 @@ int unit,type,flags; 0, 0, 5000, + NULL, flags) ); } /*******************************************************\ @@ -924,6 +882,7 @@ int unit,flags; 0, 0, 2000, + NULL, flags)); } @@ -953,7 +912,8 @@ sd_reassign_blocks(unit,block) &rbdata, sizeof(rbdata), 5000, - 0)); + NULL, + SCSI_DATA_OUT)); } #define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 ) @@ -966,7 +926,7 @@ sd_reassign_blocks(unit,block) int sd_get_parms(unit, flags) { - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; struct disk_parms *disk_parms = &sd->params; struct scsi_mode_sense scsi_cmd; struct scsi_mode_sense_data @@ -984,6 +944,7 @@ int sd_get_parms(unit, flags) /*******************************************************\ * First do a mode sense page 3 * \*******************************************************/ +#ifdef SDDEBUG if (sd_debug) { bzero(&scsi_cmd, sizeof(scsi_cmd)); @@ -1000,11 +961,13 @@ int sd_get_parms(unit, flags) &scsi_sense, sizeof(scsi_sense), 2000, - flags) != 0) + NULL, + flags | SCSI_DATA_IN) != 0) { printf("sd%d: could not mode sense (3)\n", unit); - return(ENXIO); } + else + { printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n", unit, b2tol(scsi_sense.pages.disk_format.trk_z), @@ -1017,7 +980,9 @@ int sd_get_parms(unit, flags) b2tol(scsi_sense.pages.disk_format.interleave), sd_size(unit, flags), _3btol(scsi_sense.blk_desc.blklen)); + } } +#endif /*SDDEBUG*/ /*******************************************************\ @@ -1037,14 +1002,15 @@ int sd_get_parms(unit, flags) &scsi_sense, sizeof(scsi_sense), 2000, - flags) != 0) + NULL, + flags | SCSI_DATA_IN) != 0) { - printf("sd%d: could not mode sense (4)", unit); - printf(" using ficticious geometry\n"); + printf("sd%d could not mode sense (4).", unit); + printf(" Using ficticious geometry\n"); /* * use adaptec standard ficticious geometry - * this depends on controllers and mode (ie, 1542C in - * extended bios translation is different + * this depends on which controller (e.g. 1542C is + * different. but we have to put SOMETHING here..) */ sectors = sd_size(unit, flags); disk_parms->heads = 64; @@ -1055,6 +1021,8 @@ int sd_get_parms(unit, flags) } else { + +#ifdef SDDEBUG if (sd_debug) { printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n", @@ -1064,11 +1032,13 @@ int sd_get_parms(unit, flags) b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc), b2tol(scsi_sense.pages.rigid_geometry.land_zone)); } +#endif /*SDDEBUG*/ /*******************************************************\ * KLUDGE!!(for zone recorded disks) * * give a number of sectors so that sec * trks * cyls * * is <= disk_size * + * can lead to wasted space! THINK ABOUT THIS ! * \*******************************************************/ disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads; disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2); @@ -1076,8 +1046,8 @@ int sd_get_parms(unit, flags) sectors = sd_size(unit, flags); disk_parms->disksize = sectors; - sectors /= (disk_parms->cyls * disk_parms->heads); - disk_parms->sectors = sectors; /* dubious on SCSI*/ + sectors /= (disk_parms->heads * disk_parms->cyls); + disk_parms->sectors = sectors; /* dubious on SCSI*//*XXX*/ } sd->flags |= SDVALID; @@ -1087,22 +1057,110 @@ int sd_get_parms(unit, flags) /*******************************************************\ * close the device.. only called if we are the LAST * * occurence of an open device * +* convenient now but usually a pain * \*******************************************************/ sdclose(dev) dev_t dev; { unsigned char unit, part; unsigned int old_priority; + struct sd_data *sd; unit = UNIT(dev); part = PARTITION(dev); - sd_data[unit].partflags[part] &= ~SDOPEN; - sd_data[unit].openparts &= ~(1 << part); - if(sd_data[unit].openparts == 0) /* if all partitions closed */ + sd = sd_data[unit]; + sd->partflags[part] &= ~SDOPEN; + sd->openparts &= ~(1 << part); + sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); + return(0); +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int sd_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + int retries = 0; + +#ifdef SDDEBUG + if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit); +#endif /*SDDEBUG*/ +#ifdef PARANOID + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); +#endif + if((bp = xs->bp) == NULL) { - sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK); + /***********************************************\ + * if it's a normal user level request, then ask * + * The user level code to handle error checking * + * rather than doing it here at interrupt time * + \***********************************************/ + wakeup(xs); + return; } - return(0); + + /***********************************************\ + * If it has a buf, we might be working with * + * a request from the buffer cache or some other * + * piece of code that requires us to process * + * errors right now, despite cost * + \***********************************************/ + switch(xs->error) + { + case XS_NOERROR: + bp->b_error = 0; + bp->b_resid = 0; + break; + + case XS_SENSE: + retval = (sd_interpret_sense(unit,xs)); + if(retval) + { + bp->b_flags |= B_ERROR; + bp->b_error = retval; + } + break; + + case XS_BUSY: + /*should somehow arange for a 1 sec delay here (how?)*/ + case XS_TIMEOUT: + /***********************************************\ + * If we can, resubmit it to the adapter. * + \***********************************************/ + if(xs->retries--) + { + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + if ( (*(sd_data[unit]->sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* don't wake the job, ok? */ + return; + } + xs->flags |= ITSDONE; + } /* fall through */ + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("sd%d: unknown error category from scsi driver\n" + ,unit); + } + /*******************************\ + * tell the owner we're done * + * then free our resources * + * and see if there's more work * + \*******************************/ + biodone(bp); + sd_free_xs(unit,xs,0); + sdstart(unit); /* If there's anything waiting.. do it */ } /*******************************************************\ @@ -1110,11 +1168,12 @@ dev_t dev; * Call it through the switch table, and tell it which * * sub-unit we want, and what target and lu we wish to * * talk to. Also tell it where to find the command * -* how long int is. * +* and how long it is. * * Also tell it where to read/write the data, and how * -* long the data is supposed to be * +* long the data is supposed to be. If we have a buf * +* to associate with the transfer, we need that too. * \*******************************************************/ -int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) +int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) int unit,flags; struct scsi_generic *scsi_cmd; @@ -1122,112 +1181,136 @@ int cmdlen; int timeout; u_char *data_addr; int datalen; +struct buf *bp; { struct scsi_xfer *xs; int retval; int s; - struct sd_data *sd = sd_data + unit; + struct sd_data *sd = sd_data[unit]; +#ifdef SDDEBUG if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit); - if(sd->sc_sw) /* If we have a scsi driver */ +#endif /*SDDEBUG*/ + +#ifdef PARANOID + if(!(sd->sc_sw)) /* If we have a scsi driver */ + {/* How we got here is anyone's guess */ + printf("sd%d: not set up\n",unit); + return(EINVAL); + } +#endif + xs = sd_get_xs(unit,flags); /* should wait unless booting */ +#ifdef PARANOID + if(!xs) { - xs = sd_get_xs(unit,flags); /* should wait unless booting */ - if(!xs) - { - printf("sd_scsi_cmd%d: controller busy" - " (this should never happen)\n",unit); - return(EBUSY); - } - xs->flags |= INUSE; - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = sd->ctlr; - xs->targ = sd->targ; - xs->lu = sd->lu; - xs->retries = SD_RETRIES; - xs->timeout = timeout; - xs->cmd = scsi_cmd; - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->resid = datalen; - xs->when_done = (flags & SCSI_NOMASK) - ?(int (*)())0 - :sd_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; -retry: xs->error = XS_NOERROR; - xs->bp = 0; - retval = (*(sd->sc_sw->scsi_cmd))(xs); - switch(retval) - { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); + printf("sd_scsi_cmd%d: controller busy" + " (this should never happen)\n",unit); + return(EBUSY); + } +#endif + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags = INUSE | flags; + xs->adapter = sd->ctlr; + xs->targ = sd->targ; + xs->lu = sd->lu; + xs->retries = SD_RETRIES; + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = sd_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->bp = bp; +retry: xs->error = XS_NOERROR; - case HAD_ERROR: - /*printf("err = %d ",xs->error);*/ - switch(xs->error) - { - case XS_NOERROR: - retval = ESUCCESS; - break; - case XS_SENSE: - retval = (sd_interpret_sense(unit,xs)); - break; - case XS_DRIVER_STUFFUP: - retval = EIO; - break; - case XS_TIMEOUT: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - case XS_BUSY: - if(xs->retries-- ) - { - xs->flags &= ~ITSDONE; - goto retry; - } - retval = EIO; - break; - default: - retval = EIO; - printf("sd%d: unknown error category from scsi driver\n" - ,unit); - } - break; - case COMPLETE: + /*******************************************************\ + * Do the transfer. If we are polling we will return: * + * COMPLETE, Was poll, and sd_done has been called * + * HAD_ERROR, Was poll and an error was encountered * + * TRY_AGAIN_LATER, Adapter short resources, try again * + * * + * if under full steam (interrupts) it will return: * + * SUCCESSFULLY_QUEUED, will do a wakeup when complete * + * HAD_ERROR, had an erro before it could queue * + * TRY_AGAIN_LATER, (as for polling) * + * After the wakeup, we must still check if it succeeded * + * * + * If we have a bp however, all the error proccessing * + * and the buffer code both expect us to return straight * + * to them, so as soon as the command is queued, return * + \*******************************************************/ + retval = (*(sd->sc_sw->scsi_cmd))(xs); + if(bp) return retval; /* will sleep (or not) elsewhere */ + + /*******************************************************\ + * Only here for non I/O cmds. It's cheaper to process * + * the error status here than at interrupt time so * + * sd_done will have done nothing except wake us up. * + \*******************************************************/ + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + /* fall through to check success of completed command */ + + case HAD_ERROR: + switch(xs->error) + { + case XS_NOERROR: /* nearly always hit this one */ retval = ESUCCESS; break; - case TRY_AGAIN_LATER: + + case XS_SENSE: + retval = (sd_interpret_sense(unit,xs)); + break; + case XS_BUSY: + /* should sleep 1 sec here */ + case XS_TIMEOUT: if(xs->retries-- ) { xs->flags &= ~ITSDONE; goto retry; } + case XS_DRIVER_STUFFUP: retval = EIO; break; default: retval = EIO; + printf("sd%d: unknown error category from scsi driver\n" + ,unit); + } + break; + case COMPLETE: /* Polling command completed ok */ + retval = ESUCCESS; + break; + + case TRY_AGAIN_LATER: /* adapter resource shortage */ + /* should sleep 1 sec here */ + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + goto retry; } - sd_free_xs(unit,xs,flags); - sdstart(unit); /* check if anything is waiting fr the xs */ - } - else - { - printf("sd%d: not set up\n",unit); - return(EINVAL); + default: + retval = EIO; } + /*******************************************************\ + * we have finished with the xfer stuct, free it and * + * check if anyone else needs to be started up. * + \*******************************************************/ + sd_free_xs(unit,xs,flags); + sdstart(unit); /* check queue */ return(retval); } + /***************************************************************\ * Look at the returned sense and act on the error and detirmine * * The unix error number to pass back... (0 = report no error) * @@ -1240,6 +1323,7 @@ struct scsi_xfer *xs; struct scsi_sense_data *sense; int key; int silent; + long int info; /***************************************************************\ * If the flags say errs are ok, then always return ok. * @@ -1248,6 +1332,10 @@ struct scsi_xfer *xs; silent = (xs->flags & SCSI_SILENT); sense = &(xs->sense); + info = ((sense->ext.extended.info[0] <<24)| + (sense->ext.extended.info[1] <<16)| + (sense->ext.extended.info[2] <<8)| + (sense->ext.extended.info[3] )); switch(sense->error_code & SSD_ERRCODE) { case 0x70: @@ -1263,11 +1351,7 @@ struct scsi_xfer *xs; printf("sd%d: soft error(corrected) ", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)",info); } printf("\n"); } @@ -1282,11 +1366,7 @@ struct scsi_xfer *xs; printf("sd%d: medium error ", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)",info); } printf("\n"); } @@ -1306,8 +1386,8 @@ struct scsi_xfer *xs; * sure that we don't have any residual state * \***********************************************/ if(!silent)printf("sd%d: Unit attention.\n ", unit); - sd_data[unit].flags &= ~(SDVALID | SDHAVELABEL); - if (sd_data[unit].openparts) + sd_data[unit]->flags &= ~(SDVALID | SDHAVELABEL); + if (sd_data[unit]->openparts) { return(EIO); } @@ -1319,11 +1399,7 @@ struct scsi_xfer *xs; unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1331,15 +1407,11 @@ struct scsi_xfer *xs; case 0x8: if(!silent) { - printf("sd%d: block wrong state (worm)\n ", + printf("sd%d: block wrong state (format?)\n ", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1363,11 +1435,7 @@ struct scsi_xfer *xs; unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1383,11 +1451,7 @@ struct scsi_xfer *xs; unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)\n", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("block no. %d (decimal)\n",info); } printf("\n"); } @@ -1426,7 +1490,8 @@ sdsize(dev_t dev) if (unit >= NSD) return(-1); - sd = &sd_data[unit]; + sd = sd_data[unit]; + if(!sd) return(-1); if((sd->flags & SDINIT) == 0) return(-1); if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0); @@ -1435,7 +1500,7 @@ sdsize(dev_t dev) return((int)sd->disklabel.d_partitions[part].p_size); } - +/*#define SCSIDUMP*/ #ifdef SCSIDUMP #include <vm/vm.h> /***********************************************************************\ @@ -1473,7 +1538,8 @@ sddump(dev_t dev) /* dump core after a system crash */ /* check for acceptable drive number */ if (unit >= NSD) return(ENXIO); /* 31 Jul 92*/ - sd = sd_data+unit; + sd = sd_data[unit]; + if(!sd) return (ENXIO); /* was it ever initialized etc. ? */ if (!(sd->flags & SDINIT)) return (ENXIO); if (sd->flags & SDVALID != SDVALID) return (ENXIO) ; @@ -1503,7 +1569,7 @@ sddump(dev_t dev) /* dump core after a system crash */ trunc_page(addr), VM_PROT_READ, TRUE); -#ifndef NOT_TRUSTED +#ifndef NOT_TRUSTED /*******************************************************\ * Fill out the scsi command * \*******************************************************/ @@ -1552,8 +1618,9 @@ sddump(dev_t dev) /* dump core after a system crash */ return(ENXIO); /* we said not to sleep! */ } #else NOT_TRUSTED + /* lets just talk about this first...*/ printf ("sd%d: dump addr 0x%x, blk %d\n",unit,addr,blknum); -#endif +#endif NOT_TRUSTED if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ; /* update block count */ @@ -1567,11 +1634,12 @@ sddump(dev_t dev) /* dump core after a system crash */ } return(0); } -#else /* No SCSIDUMP CODE */ +#else SCSIDUMP sddump() { printf("\nsddump() -- not implemented\n"); - DELAY(20000000); /* 100 seconds */ + DELAY(100000000); /* 100 seconds */ return(-1); } -#endif +#endif SCSIDUMP + diff --git a/sys/scsi/st.c b/sys/scsi/st.c index e355967..75f994b 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -12,12 +12,25 @@ * 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: 1 00098 + * -------------------- ----- ---------------------- + * + * 16 Feb 93 Julian Elischer ADDED for SCSI system + * 1.15 is the last verion to support MACH and OSF/1 + */ +/* $Revision: 1.23 $ */ + +/* * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993 * - * $Id$ + * $Id: st.c,v 1.23 93/08/26 21:09:51 julian Exp Locker: julian $ */ + /* * To do: * work out some better way of guessing what a good timeout is going @@ -33,14 +46,12 @@ #include <sys/errno.h> #include <sys/ioctl.h> +#include <sys/malloc.h> #include <sys/buf.h> #include <sys/proc.h> #include <sys/user.h> #include <sys/mtio.h> -#if defined(OSF) -#define SECSIZE 512 -#endif /* defined(OSF) */ #include <scsi/scsi_all.h> #include <scsi/scsi_tape.h> @@ -91,6 +102,7 @@ struct rogues #define ST_Q_NEEDS_PAGE_0 0x00001 #define ST_Q_FORCE_FIXED_MODE 0x00002 #define ST_Q_FORCE_VAR_MODE 0x00004 +#define ST_Q_SNS_HLP 0x00008 static struct rogues gallery[] = /* ends with an all null entry */ { @@ -110,6 +122,14 @@ static struct rogues gallery[] = /* ends with an all null entry */ {0,QIC_120} /* minor 12,13,14,15*/ } }, + { "Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462","-005", + 0, + { {ST_Q_SNS_HLP,0}, /* minor 0,1,2,3*/ + {ST_Q_SNS_HLP,QIC_525}, /* minor 4,5,6,7*/ + {0,QIC_150}, /* minor 8,9,10,11*/ + {0,QIC_120} /* minor 12,13,14,15*/ + } + }, { "Archive Viper 150", "ARCHIVE ", "VIPER 150","????", ST_Q_NEEDS_PAGE_0, { {0,0}, /* minor 0,1,2,3*/ @@ -118,28 +138,26 @@ static struct rogues gallery[] = /* ends with an all null entry */ {0,QIC_24} /* minor 12,13,14,15*/ } }, + { "Wangdat Dat (1.3GB)", "WangDAT ", "Model 1300","????", + 0, + { {ST_Q_FORCE_VAR_MODE,0}, /* minor 0,1,2,3*/ + {ST_Q_SNS_HLP,0}, /* minor 4,5,6,7*/ + {ST_Q_FORCE_FIXED_MODE,0}, /* minor 8,9,10,11*/ + {ST_Q_FORCE_VAR_MODE,0} /* minor 12,13,14,15*/ + } + }, {(char *)0} }; -#ifndef __386BSD__ -struct buf stbuf[NST][STQSIZE]; /* buffer for raw io (one per device) */ -struct buf *stbuf_free[NST]; /* queue of free buffers for raw io */ -#endif __386BSD__ -struct buf st_buf_queue[NST]; int ststrategy(); void stminphys(); -struct scsi_xfer st_scsi_xfer[NST]; -int st_xfer_block_wait[NST]; -#if defined(OSF) -caddr_t st_window[NST]; -#endif /* defined(OSF) */ -#ifndef MACH #define ESUCCESS 0 -#endif MACH -int st_debug = 0; +#ifdef STDEBUG +int st_debug = 1; +#endif /*STDEBUG*/ int stattach(); int st_done(); @@ -171,18 +189,26 @@ struct st_data /*--------------------storage for sense data returned by the drive------------*/ unsigned char sense_data[12]; /* additional sense data needed */ /* for mode sense/select. */ -}st_data[NST]; + struct buf *buf_queue; /* the queue of pending IO operations */ + struct scsi_xfer scsi_xfer; /* The scsi xfer struct for this drive*/ + int xfer_block_wait; /* whether there is a process waiting */ +}*st_data[NST]; #define ST_INITIALIZED 0x01 #define ST_INFO_VALID 0x02 #define ST_OPEN 0x04 +#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */ #define ST_WRITTEN 0x10 #define ST_FIXEDBLOCKS 0x20 #define ST_AT_FILEMARK 0x40 -#define ST_AT_EOM 0x80 +#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data)*/ +#define ST_AT_BOM 0x100 /* ops history suggests Beg of Medium */ +#define ST_READONLY 0x200 /* st_mode_sense says write protected */ -#define ST_PER_ACTION (ST_AT_FILEMARK | ST_AT_EOM) -#define ST_PER_OPEN (ST_OPEN | ST_WRITTEN | ST_PER_ACTION) -#define ST_PER_MEDIA ST_FIXEDBLOCKS +#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING) +#define ST_PER_OPEN (ST_OPEN | ST_PER_ACTION) +#define ST_PER_MEDIA (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \ + ST_FIXEDBLOCKS | ST_AT_BOM | ST_READONLY | \ + ST_PER_ACTION) static int next_st_unit = 0; /***********************************************************************\ @@ -196,7 +222,9 @@ struct scsi_switch *scsi_switch; int unit,i; struct st_data *st; +#ifdef STDEBUG if(scsi_debug & PRINTROUTINES) printf("stattach: "); +#endif /*STDEBUG*/ /*******************************************************\ * Check we have the resources for another drive * \*******************************************************/ @@ -207,7 +235,17 @@ struct scsi_switch *scsi_switch; (unit + 1),NST); return(0); } - st = st_data + unit; + if(st_data[unit]) + { + printf("st%d: Already has storage!\n",unit); + return(0); + } + st = st_data[unit] = malloc(sizeof(struct st_data),M_DEVBUF,M_NOWAIT); + if(!st) + { + printf("st%d: malloc failed in st.c\n",unit); + return(0); + } /*******************************************************\ * Store information needed to contact our base driver * \*******************************************************/ @@ -236,37 +274,35 @@ struct scsi_switch *scsi_switch; \*******************************************************/ if(st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { - if(st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) + printf("st%d: drive offline\n", unit); + } + else + { + if(!st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) { - printf("st%d: tape present: %d blocks of %d bytes\n", - unit, st->numblks, st->media_blksiz); + printf("st%d: density code 0x%x, ", + unit, st->media_density); + if (st->media_blksiz) + { + printf("%d-byte", st->media_blksiz); + } + else + { + printf("variable"); + } + printf(" blocks, write-%s\n", + st->flags & ST_READONLY ? "protected" : "enabled"); } else { printf("st%d: drive empty\n", unit); } } - else - { - printf("st%d: drive offline\n", unit); - } /*******************************************************\ * Set up the bufs for this device * \*******************************************************/ -#ifndef __386BSD__ - stbuf_free[unit] = (struct buf *)0; - for (i = 1; i < STQSIZE; i++) - { - stbuf[unit][i].b_forw = stbuf_free[unit]; - stbuf_free[unit]=&stbuf[unit][i]; - } -#endif __386BSD__ - st_buf_queue[unit].b_active = 0; - st_buf_queue[unit].b_actf = st_buf_queue[unit].b_actl = 0; + st->buf_queue = 0; -#if defined(OSF) - st_window[unit] = (caddr_t)alloc_kva(SECSIZE*256+PAGESIZ); -#endif /* defined(OSF) */ st->flags |= ST_INITIALIZED; return; @@ -282,7 +318,7 @@ st_identify_drive(unit) int unit; { - struct st_data *st; + struct st_data *st = st_data[unit]; struct scsi_inquiry_data inqbuf; struct rogues *finger; char manu[32]; @@ -292,7 +328,6 @@ int unit; int model_len; - st = st_data + unit; /*******************************************************\ * Get the device type information * \*******************************************************/ @@ -335,7 +370,10 @@ int unit; } model2[model_len] = 0; if ((strcmp(manu, finger->manu) == 0 ) - && (strcmp(model2, finger->model) == 0 )) + && (strcmp(model2, finger->model) == 0 || + strcmp("????????????????", finger->model) == 0) + && (strcmp(version, finger->version) == 0 || + strcmp("????", finger->version) == 0)) { printf("st%d: %s is a known rogue\n", unit,finger->name); st->modes[0] = finger->modes[0]; @@ -359,11 +397,11 @@ int unit; stopen(dev) { int unit,mode,dsty; + int errno = 0; struct st_data *st; unit = UNIT(dev); mode = MODE(dev); dsty = DSTY(dev); - st = st_data + unit; /*******************************************************\ * Check the unit is legal * @@ -372,6 +410,13 @@ stopen(dev) { return(ENXIO); } + st = st_data[unit]; + /*******************************************************\ + * Make sure the device has been initialised * + \*******************************************************/ + if ((st == NULL) || (!(st->flags & ST_INITIALIZED))) + return(ENXIO); + /*******************************************************\ * Only allow one at a time * \*******************************************************/ @@ -379,103 +424,151 @@ stopen(dev) { return(ENXIO); } + + /*******************************************************\ + * Throw out a dummy instruction to catch 'Unit attention* + * errors (the error handling will invalidate all our * + * device info if we get one, but otherwise, ignore it * + \*******************************************************/ + st_test_ready(unit, 0); + + /***************************************************************\ + * Check that the device is ready to use (media loaded?) * + * This time take notice of the return result * + \***************************************************************/ + if(errno = (st_test_ready(unit,0))) + { + printf("st%d: not ready\n",unit); + return(errno); + } + /*******************************************************\ * Set up the mode flags according to the minor number * * ensure all open flags are in a known state * * if it's a different mode, dump all cached parameters * \*******************************************************/ - if(st->last_dsty != dsty) + if(st->last_dsty != dsty || !(st->flags & ST_INFO_VALID)) + { st->flags &= ~ST_INFO_VALID; - st->last_dsty = dsty; + st->last_dsty = dsty; + st->quirks = st->drive_quirks | st->modes[dsty].quirks; + st->density = st->modes[dsty].density; + } st->flags &= ~ST_PER_OPEN; - st->quirks = st->drive_quirks | st->modes[dsty].quirks; - st->density = st->modes[dsty].density; +#ifdef STDEBUG if(scsi_debug & (PRINTROUTINES | TRACEOPENS)) printf("stopen: dev=0x%x (unit %d (of %d))\n" , dev, unit, NST); - /*******************************************************\ - * Make sure the device has been initialised * - \*******************************************************/ - if (!(st->flags & ST_INITIALIZED)) - return(ENXIO); - - /*******************************************************\ - * Check that it is still responding and ok. * - \*******************************************************/ -#ifdef removing_this - if(scsi_debug & TRACEOPENS) - printf("device is "); - if (!(st_req_sense(unit, 0))) /* may get a 'unit attention' if new */ - { - if(scsi_debug & TRACEOPENS) - printf("not responding\n"); - return(ENXIO); - } - if(scsi_debug & TRACEOPENS) - printf("ok\n"); -#endif - if(!(st_test_ready(unit,0))) - { - printf("st%d: not ready\n",unit); - return(EIO); - } - if(!(st_test_ready(unit,0))) /* first may get 'unit attn' */ - { - printf("st%d: not ready\n",unit); - return(EIO); - } - +#endif /*STDEBUG*/ /***************************************************************\ * If the media is new, then make sure we give it a chance to * - * to do a 'load' instruction. Possibly the test ready * - * may not read true until this is done.. check this! XXX * + * to do a 'load' instruction. * \***************************************************************/ if(!(st->flags & ST_INFO_VALID)) /* is media new? */ { - if(!st_load(unit,LD_LOAD,0)) + if(errno = st_load(unit,LD_LOAD,0)) { - return(EIO); + return(errno); + } + if(st->quirks & ST_Q_SNS_HLP) + { + /***********************************************\ + * The quirk here is that the drive returns some * + * value to st_mode_sense incorrectly until the * + * tape has actually passed by the head. * + * * + * The method is to set the drive to fixed-block * + * state (user-specified density and 512-byte * + * blocks), then read and rewind to get it to * + * sense the tape. If the sense interpretation * + * code determines that the tape contains * + * variable-length blocks, set to variable-block * + * state and try again. The result will be the * + * ability to do an accurate st_mode_sense. * + * * + * We pretend not to be at beginning of medium * + * to keep st_read from calling st_decide_mode. * + * * + * We know we can do a rewind because we just * + * did a load, which implies rewind. Rewind * + * seems preferable to space backward if we have * + * a virgin tape. * + * * + * This is really a check fr 512 byte records * + * Needs more thought * + \***********************************************/ + char *buf; + + buf = malloc(DEF_FIXED_BSIZE,M_TEMP,M_NOWAIT); + if(!buf) return(ENOMEM); + + if (errno = st_mode_sense(unit, 0)) + { + free(buf,M_TEMP); + return(errno); + } + st->blksiz = DEF_FIXED_BSIZE; + st->flags = ~ST_AT_BOM & st->flags | ST_FIXEDBLOCKS; + if (errno = st_mode_select(unit, 0)) + { + free(buf,M_TEMP); + return(errno); + } + st_read(unit, buf, DEF_FIXED_BSIZE, 0); + if (errno = st_rewind(unit, FALSE, 0)) + { + free(buf,M_TEMP); + return(errno); + } + if (st->blksiz == 0) /* set it back the way it was */ + { + st->flags &= ~(ST_FIXEDBLOCKS | ST_AT_BOM); + if (errno = st_mode_select(unit, 0)) + { + free(buf,M_TEMP); + return(errno); + } + st_read(unit, buf, 1, 0); + if (errno = st_rewind(unit, FALSE, 0)) + { + free(buf,M_TEMP); + return(errno); + } + } + free(buf,M_TEMP); } } +#ifdef removing_this +#endif removing_this + /*******************************************************\ * Load the physical device parameters * * loads: blkmin, blkmax * \*******************************************************/ - if(!st_rd_blk_lim(unit,0)) + if(errno = st_rd_blk_lim(unit,0)) { - return(EIO); + return(errno); } /*******************************************************\ * Load the media dependent parameters * * includes: media_blksiz,media_density,numblks * \*******************************************************/ - if(!st_mode_sense(unit,0)) + if(errno = st_mode_sense(unit,0)) { - return(EIO); - } - - /*******************************************************\ - * From media parameters, device parameters and quirks, * - * work out how we should be setting outselves up * - \*******************************************************/ - if(! st_decide_mode(unit)) - return(ENXIO); - - if(!st_mode_select(unit,0,st->density)) - { - return(EIO); + return(errno); } st->flags |= ST_INFO_VALID; st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */ +#ifdef STDEBUG if(scsi_debug & TRACEOPENS) printf("Params loaded "); - +#endif /*STDEBUG*/ st->flags |= ST_OPEN; return(0); @@ -492,35 +585,41 @@ stclose(dev) unit = UNIT(dev); mode = MODE(dev); - st = st_data + unit; + st = st_data[unit]; +#ifdef STDEBUG if(scsi_debug & TRACEOPENS) printf("Closing device"); +#endif /*STDEBUG*/ if(st->flags & ST_WRITTEN) { st_write_filemarks(unit,1,0); } - st->flags &= ~ST_WRITTEN; switch(mode) { case 0: st_rewind(unit,FALSE,SCSI_SILENT); st_prevent(unit,PR_ALLOW,SCSI_SILENT); + st->flags &= ~ST_PER_MEDIA; break; - case 1: - st_prevent(unit,PR_ALLOW,SCSI_SILENT); + case 1: /*non rewind*/ + /* possibly space forward if not already at EOF? */ + /* (fixed block mode only) */ + break; case 2: st_rewind(unit,FALSE,SCSI_SILENT); st_prevent(unit,PR_ALLOW,SCSI_SILENT); st_load(unit,LD_UNLOAD,SCSI_SILENT); + st->flags &= ~ST_PER_MEDIA; break; - case 3: + case 3:/* a bit silly really */ st_prevent(unit,PR_ALLOW,SCSI_SILENT); st_load(unit,LD_UNLOAD,SCSI_SILENT); + st->flags &= ~ST_PER_MEDIA; break; default: - printf("st%d:close: Bad mode (minor number)%d how's it open?\n" + printf("st%d: close: Bad mode (minor number)%d how's it open?\n" ,unit,mode); return(EINVAL); } @@ -529,137 +628,207 @@ stclose(dev) } /***************************************************************\ -* Given all we know about the device, media, mode and 'quirks', * -* make a decision as to how we should be set up. * +* Given all we know about the device, media, mode, 'quirks' and * +* initial operation, make a decision as to how we should be set * +* up. First, choose the density, then variable/fixed blocks. * \***************************************************************/ -st_decide_mode(unit) -int unit; +st_decide_mode(unit, first_read) +int unit, first_read; { - struct st_data *st = st_data + unit; + int dsty, error; + struct st_data *st = st_data[unit]; - if(st->flags & ST_INFO_VALID) return TRUE; + /***************************************************************\ + * First, if our information about the tape is out of date, get * + * new information. * + \***************************************************************/ + if (!(st->flags & ST_INFO_VALID)) + { + if (error = st_mode_sense(unit, 0)) + return (error); + st->flags |= ST_INFO_VALID; + } +#ifdef STDEBUG + if(st_debug) printf("starting mode decision\n"); +#endif /*STDEBUG*/ - switch(st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) + /***************************************************************\ + * Second, set the density, and set the quirk flags as a * + * function of the density. * + \***************************************************************/ + st->quirks = st->drive_quirks; + dsty = st->last_dsty; /* set in the open call */ + if (dsty > 0) + { + /*******************************************************\ + * If the user specified the density, believe him. * + \*******************************************************/ + st->density = st->modes[dsty].density; + st->quirks |= st->modes[dsty].quirks; + } + else { - case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): - printf("st%d: bad quirks\n",unit); - return FALSE; - case 0: - switch(st->density) - { - case QIC_120: - case QIC_150: - goto fixed; - case HALFINCH_800: - case HALFINCH_1600: - case HALFINCH_6250: - case QIC_525: - goto var; - default: - break; - } /*******************************************************\ - * There was once a reason that the tests below were * - * deemed insufficient, but I can't remember why.. * - * If your drive needs these added to, let me know * - * and/or add a rogue entry. * + * If the user defaulted the density, use the drive's * + * opinion of it. * \*******************************************************/ - if(st->blkmin && (st->blkmin == st->blkmax)) - goto fixed; - if(st->blkmin != st->blkmax) - goto var; + st->density = st->media_density; + do { + if (st->density == st->modes[dsty].density) + { + st->quirks |= st->modes[dsty].quirks; +#ifdef STDEBUG + if(st_debug) printf("selected density %d\n",dsty); +#endif /*STDEBUG*/ + break; /* only out of the loop*/ + } + } while (++dsty < 4); + /*******************************************************\ + * If dsty got to 4, the drive must have reported a * + * density which isn't in our density list (e.g. QIC-24 * + * for a default drive). We can handle that, except * + * there'd better be no density-specific quirks in the * + * drive's behavior. * + \*******************************************************/ + } + + /***************************************************************\ + * If the user has already specified fixed or variable-length * + * blocks using an ioctl, just believe him. OVERRIDE ALL * + \***************************************************************/ + if (st->flags & ST_BLOCK_SET) + { +#ifdef STDEBUG + if(st_debug) printf("user has specified %s\n", + st->flags & ST_FIXEDBLOCKS ? "variable mode" : "fixed mode"); +#endif /*STDEBUG*/ + goto done; + } + /***************************************************************\ + * If the user hasn't already specified fixed or variable-length * + * blocks and the block size (zero if variable-length), we'll * + * have to try to figure them out ourselves. * + * * + * Our first shot at a method is, "The quirks made me do it!" * + \***************************************************************/ + switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE)) + { + case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE): + printf("st%d: bad quirks\n",unit); + return (EINVAL); case ST_Q_FORCE_FIXED_MODE: -fixed: st->flags |= ST_FIXEDBLOCKS; - if(st->media_blksiz) - { + if (st->blkmin && st->blkmin == st->blkmax) + st->blksiz = st->blkmin; + else if(st->media_blksiz > 0) st->blksiz = st->media_blksiz; - } else - { - if(st->blkmin) - { - st->blksiz = st->blkmin; /* just to make sure */ - } - else - { - st->blksiz = DEF_FIXED_BSIZE; - } - } - break; + st->blksiz = DEF_FIXED_BSIZE; +#ifdef STDEBUG + if(st_debug) printf("Quirks force fixed mode\n"); +#endif /*STDEBUG*/ + goto done; case ST_Q_FORCE_VAR_MODE: -var: st->flags &= ~ST_FIXEDBLOCKS; st->blksiz = 0; - break; +#ifdef STDEBUG + if(st_debug) printf("Quirks force variable mode\n"); +#endif /*STDEBUG*/ + goto done; } - return(TRUE); -} -#ifndef __386BSD__ -/*******************************************************\ -* Get ownership of this unit's buf * -* If need be, sleep on it, until it comes free * -\*******************************************************/ -struct buf * -st_get_buf(unit) { - struct buf *rc; - - while (!(rc = stbuf_free[unit])) - sleep((caddr_t)&stbuf_free[unit], PRIBIO+1); - stbuf_free[unit] = stbuf_free[unit]->b_forw; - rc->b_error = 0; - rc->b_resid = 0; - rc->b_flags = 0; - return(rc); -} -/*******************************************************\ -* Free this unit's buf, wake processes waiting for it * -\*******************************************************/ -st_free_buf(unit,bp) -struct buf *bp; -{ - if (!stbuf_free[unit]) - wakeup((caddr_t)&stbuf_free[unit]); - bp->b_forw = stbuf_free[unit]; - stbuf_free[unit] = bp; -} - + /***************************************************************\ + * If the drive can only handle fixed-length blocks and only at * + * one size, perhaps we should just do that. * + \***************************************************************/ + if (st->blkmin && (st->blkmin == st->blkmax)) + { + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = st->blkmin; +#ifdef STDEBUG + if(st_debug) printf("blkmin == blkmax of %d\n",st->blkmin); +#endif /*STDEBUG*/ + goto done; + } -/*******************************************************\ -* Get the buf for this unit and use physio to do it * -\*******************************************************/ -stread(dev,uio) -register short dev; -struct uio *uio; -{ - int unit = UNIT(dev); - struct buf *bp = st_get_buf(unit); - int rc; - rc = physio(ststrategy, bp, dev, B_READ, stminphys, uio); - st_free_buf(unit,bp); - return(rc); -} + /***************************************************************\ + * If the tape density mandates use of fixed or variable-length * + * blocks, comply. * + \***************************************************************/ + switch (st->density) + { + case HALFINCH_800: + case HALFINCH_1600: + case HALFINCH_6250: + st->flags &= ~ST_FIXEDBLOCKS; + st->blksiz = 0; +#ifdef STDEBUG + if(st_debug) printf("density specified variable\n"); +#endif /*STDEBUG*/ + goto done; + case QIC_11: + case QIC_24: + case QIC_120: + case QIC_150: + st->flags |= ST_FIXEDBLOCKS; + if (st->media_blksiz > 0) + st->blksiz = st->media_blksiz; + else + st->blksiz = DEF_FIXED_BSIZE; +#ifdef STDEBUG + if(st_debug) printf("density specified fixed\n"); +#endif /*STDEBUG*/ + goto done; + } -/*******************************************************\ -* Get the buf for this unit and use physio to do it * -\*******************************************************/ -stwrite(dev,uio) -dev_t dev; -struct uio *uio; -{ - int unit = UNIT(dev); - struct buf *bp = st_get_buf(unit); - int rc; + /***************************************************************\ + * If we're about to read the tape, perhaps we should choose * + * fixed or variable-length blocks and block size according to * + * what the drive found on the tape. * + * ****though it probably hasn't looked yet!**** * + \***************************************************************/ + if (first_read) + { + if (st->media_blksiz == 0) + st->flags &= ~ST_FIXEDBLOCKS; + else + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = st->media_blksiz; +#ifdef STDEBUG + if(st_debug) printf("Used media_blksiz of %d\n",st->media_blksiz); +#endif /*STDEBUG*/ + goto done; + } - rc = physio(ststrategy, bp, dev, B_WRITE, stminphys, uio); - st_free_buf(unit,bp); - return(rc); -} + /***************************************************************\ + * If the drive says it can handle variable size blocks * + * and nothing has been specified until now, hey let's do it * + \***************************************************************/ + if (st->blkmin != st->blkmax) + { + st->flags &= ~ST_FIXEDBLOCKS; + st->blksiz = 0; +#ifdef STDEBUG + if(st_debug) printf("blkmin != blkmax\n, select variable\n"); +#endif /*STDEBUG*/ + goto done; + } + /***************************************************************\ + * We're getting no hints from any direction. Choose fixed- * + * length blocks arbitrarily. * + \***************************************************************/ + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = DEF_FIXED_BSIZE; +#ifdef STDEBUG + if(st_debug) printf("Give up and default to fixed mode\n"); +#endif /*STDEBUG*/ +done: + st->flags &= ~ST_AT_BOM; + return (st_mode_select(unit, 0)); +} -#endif __386BSD__ /*******************************************************\ * trim the size of the transfer if needed, * * called by physio * @@ -669,7 +838,7 @@ struct uio *uio; void stminphys(bp) struct buf *bp; { - (*(st_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp); + (*(st_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp); } /*******************************************************\ @@ -682,15 +851,19 @@ struct buf *bp; int ststrategy(bp) struct buf *bp; { - struct buf *dp; + struct buf **dp; unsigned char unit; unsigned int opri; + struct st_data *st; ststrats++; unit = UNIT((bp->b_dev)); + st = st_data[unit]; +#ifdef STDEBUG if(scsi_debug & PRINTROUTINES) printf("\nststrategy "); if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n", unit,bp->b_bcount,bp->b_blkno); +#endif /*STDEBUG*/ /*******************************************************\ * If it's a null transfer, return immediatly * \*******************************************************/ @@ -700,45 +873,53 @@ struct buf *bp; } /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && + (bp->b_error = st_decide_mode(unit, (bp->b_flags & B_READ) != 0))) + goto bad; + + /*******************************************************\ * Odd sized request on fixed drives are verboten * \*******************************************************/ - if(st_data[unit].flags & ST_FIXEDBLOCKS) + if(st->flags & ST_FIXEDBLOCKS) { - if(bp->b_bcount % st_data[unit].blksiz) + if(bp->b_bcount % st->blksiz) { printf("st%d: bad request, must be multiple of %d\n", - unit, st_data[unit].blksiz); + unit, st->blksiz); bp->b_error = EIO; goto bad; } } /*******************************************************\ - * as are too-short requests on variable length drives. * + * as are out-of-range requests on variable drives. * \*******************************************************/ - else if(bp->b_bcount < st_data[unit].blkmin) + else if(bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) { - printf("st%d: bad request, must not be less than %d\n", - unit, st_data[unit].blkmin); + printf("st%d: bad request, must be between %d and %d\n", + unit, st->blkmin, st->blkmax); bp->b_error = EIO; goto bad; } -#ifdef __386BSD__ stminphys(bp); -#endif __386BSD__ opri = splbio(); - dp = &st_buf_queue[unit]; /*******************************************************\ - * Place it in the queue of disk activities for this tape* - * at the end * + * Place it in the queue of activities for this tape * + * at the end (a bit silly because we only have on user..* + * (but it could fork() )) * \*******************************************************/ - while ( dp->b_actf) + dp = &(st->buf_queue); + while (*dp) { - dp = dp->b_actf; + dp = &((*dp)->b_actf); } - dp->b_actf = bp; - bp->b_actf = NULL; + *dp = bp; + bp->b_actf = NULL, /*******************************************************\ * Tell the device to get going on the transfer if it's * @@ -760,371 +941,7 @@ done: } -/***************************************************************\ -* ststart 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 st_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 (ststrategy) * -* * -* 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. * -\***************************************************************/ -/* ststart() is called at splbio */ -ststart(unit) -{ - int drivecount; - register struct buf *bp = 0; - register struct buf *dp; - struct scsi_xfer *xs; - struct scsi_rw_tape cmd; - int blkno, nblk; - struct st_data *st; - - - st = st_data + unit; - - if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit); - /*******************************************************\ - * See if there is a buf to do and we are not already * - * doing one * - \*******************************************************/ - xs=&st_scsi_xfer[unit]; - if(xs->flags & INUSE) - { - return; /* unit already underway */ - } -trynext: - if(st_xfer_block_wait[unit]) /* a special awaits, let it proceed first */ - { - wakeup(&st_xfer_block_wait[unit]); - return; - } - - dp = &st_buf_queue[unit]; - if ((bp = dp->b_actf) != NULL) - { - dp->b_actf = bp->b_actf; - } - else /* no work to do */ - { - return; - } - xs->flags = INUSE; /* Now ours */ - - - /*******************************************************\ - * We have a buf, now we should move the data into * - * a scsi_xfer definition and try start it * - \*******************************************************/ - - /*******************************************************\ - * If we are at a filemark but have not reported it yet * - * then we should report it now * - \*******************************************************/ - if(st->flags & ST_AT_FILEMARK) - { - bp->b_error = 0; - bp->b_flags |= B_ERROR; /* EOF*/ - st->flags &= ~ST_AT_FILEMARK; - biodone(bp); - xs->flags = 0; /* won't need it now */ - goto trynext; - } - /*******************************************************\ - * If we are at EOM but have not reported it yet * - * then we should report it now * - \*******************************************************/ - if(st->flags & ST_AT_EOM) - { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - st->flags &= ~ST_AT_EOM; - biodone(bp); - xs->flags = 0; /* won't need it now */ - goto trynext; - } - /*******************************************************\ - * Fill out the scsi command * - \*******************************************************/ - bzero(&cmd, sizeof(cmd)); - if((bp->b_flags & B_READ) == B_WRITE) - { - st->flags |= ST_WRITTEN; - xs->flags |= SCSI_DATA_OUT; - } - else - { - xs->flags |= SCSI_DATA_IN; - } - cmd.op_code = (bp->b_flags & B_READ) - ? READ_COMMAND_TAPE - : WRITE_COMMAND_TAPE; - - /*******************************************************\ - * Handle "fixed-block-mode" tape drives by using the * - * block count instead of the length. * - \*******************************************************/ - if(st->flags & ST_FIXEDBLOCKS) - { - cmd.byte2 |= SRWT_FIXED; - lto3b(bp->b_bcount/st->blksiz,cmd.len); - } - else - { - lto3b(bp->b_bcount,cmd.len); - } - - /*******************************************************\ - * Fill out the scsi_xfer structure * - * Note: we cannot sleep as we may be an interrupt * - \*******************************************************/ - xs->flags |= SCSI_NOSLEEP; - xs->adapter = st->ctlr; - xs->targ = st->targ; - xs->lu = st->lu; - xs->retries = 1; /* can't retry on tape*/ - xs->timeout = 100000; /* allow 100 secs for retension */ - xs->cmd = (struct scsi_generic *)&cmd; - xs->cmdlen = sizeof(cmd); - xs->data = (u_char *)bp->b_un.b_addr; - xs->datalen = bp->b_bcount; - xs->resid = bp->b_bcount; - xs->when_done = st_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; - xs->error = XS_NOERROR; - xs->bp = bp; - /*******************************************************\ - * Pass all this info to the scsi driver. * - \*******************************************************/ - - -#if defined(OSF)||defined(FIX_ME) - if (bp->b_flags & B_PHYS) { - xs->data = (u_char*)map_pva_kva(bp->b_proc, bp->b_un.b_addr, - bp->b_bcount, st_window[unit], - (bp->b_flags&B_READ)?B_WRITE:B_READ); - } else { - xs->data = (u_char*)bp->b_un.b_addr; - } -#endif /* defined(OSF) */ - - if ( (*(st->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED) - { - printf("st%d: oops not queued",unit); - xs->error = XS_DRIVER_STUFFUP; - st_done(unit,xs); - } - stqueues++; -} - -/*******************************************************\ -* This routine is called by the scsi interrupt when * -* the transfer is complete. -\*******************************************************/ -int st_done(unit,xs) -int unit; -struct scsi_xfer *xs; -{ - struct buf *bp; - int retval; - - if(scsi_debug & PRINTROUTINES) printf("st_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_flags &= ~B_ERROR; - bp->b_error = 0; - bp->b_resid = 0; - break; - case XS_SENSE: - retval = (st_interpret_sense(unit,xs)); - if(retval) - { - /***************************************\ - * We have a real error, the bit should * - * be set to indicate this. The return * - * value will contain the unix error code* - * that the error interpretation routine * - * thought was suitable, so pass this * - * value back in the buf structure. * - * Furthermore we return information * - * saying that no data was transferred * - \***************************************/ - bp->b_flags |= B_ERROR; - bp->b_error = retval; - bp->b_resid = bp->b_bcount; - st_data[unit].flags - &= ~(ST_AT_FILEMARK|ST_AT_EOM); - } - else - { - /***********************************************\ - * The error interpretation code has declared * - * that it wasn't a real error, or at least that * - * we should be ignoring it if it was. * - \***********************************************/ - if(!(xs->resid)) - { - /***************************************\ - * we apparently had a corrected error * - * or something. * - * pretend the error never happenned * - \***************************************/ - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - bp->b_resid = 0; - break; - } - if ( xs->resid != xs->datalen ) - { - /***************************************\ - * Here we have the tricky part.. * - * We successfully read less data than * - * we requested. (but not 0) * - *------for variable blocksize tapes:----* - * UNDER 386BSD: * - * We should legitimatly have the error * - * bit set, with the error value set to * - * zero.. This is to indicate to the * - * physio code that while we didn't get * - * as much information as was requested, * - * we did reach the end of the record * - * and so physio should not call us * - * again for more data... we have it all * - * SO SET THE ERROR BIT! * - * * - * UNDER MACH (CMU) and NetBSD: * - * To indicate the same as above, we * - * need only have a non 0 resid that is * - * less than the b_bcount, but the * - * ERROR BIT MUST BE CLEAR! (sigh) * - * * - * UNDER OSF1: * - * To indicate the same as above, we * - * need to have a non 0 resid that is * - * less than the b_bcount, but the * - * ERROR BIT MUST BE SET! (gasp)(sigh) * - * * - *-------for fixed blocksize device------* - * We could have read some successful * - * records before hitting * - * the EOF or EOT. These must be passed * - * to the user, before we report the * - * EOx. Only if there is no data for the * - * user do we report it now. (via an EIO * - * for EOM and resid == count for EOF). * - * We will report the EOx NEXT time.. * - \***************************************/ -/* how do I distinguish NetBSD? at present it's wrong for NetBsd */ -#ifdef MACH /*osf and cmu varieties */ -#ifdef OSF - bp->b_flags |= B_ERROR; -#else OSF - bp->b_flags &= ~B_ERROR; -#endif OSF -#endif MACH -#ifdef __386BSD__ - bp->b_flags |= B_ERROR; -#endif __386BSD__ - bp->b_error = 0; - bp->b_resid = xs->resid; - if((st_data[unit].flags & ST_FIXEDBLOCKS)) - { - bp->b_resid *= st_data[unit].blksiz; - if( (st_data[unit].flags & ST_AT_EOM) - && (bp->b_resid == bp->b_bcount)) - { - bp->b_error = EIO; - st_data[unit].flags - &= ~ST_AT_EOM; - } - } - xs->error = XS_NOERROR; - break; - } - else - { - /***************************************\ - * We have come out of the error handler * - * with no error code.. we have also * - * not had an ili (would have gone to * - * the previous clause). Now we need to * - * distiguish between succesful read of * - * no data (EOF or EOM) and successfull * - * read of all requested data. * - * At least all o/s agree that: * - * 0 bytes read with no error is EOF * - * 0 bytes read with an EIO is EOM * - \***************************************/ - - bp->b_resid = bp->b_bcount; - if(st_data[unit].flags & ST_AT_FILEMARK) - { - st_data[unit].flags &= ~ST_AT_FILEMARK; - bp->b_flags &= ~B_ERROR; - bp->b_error = 0; - break; - } - if(st_data[unit].flags & ST_AT_EOM) - { - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - st_data[unit].flags &= ~ST_AT_EOM; - break; - } - } - } - break; - - case XS_TIMEOUT: - printf("st%d timeout\n",unit); - break; - - 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->flags &= ~ITSDONE; - xs->error = XS_NOERROR; - if ( (*(st_data[unit].sc_sw->scsi_cmd))(xs) - == SUCCESSFULLY_QUEUED) - { /* don't wake the job, ok? */ - return; - } - printf("st%d: device busy\n", unit); - xs->flags |= ITSDONE; - } - case XS_DRIVER_STUFFUP: - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - break; - default: - printf("st%d: unknown error category from scsi driver\n" - ,unit); - } - biodone(bp); - xs->flags = 0; /* no longer in use */ - ststart(unit); /* If there's another waiting.. do it */ - } - else - { - wakeup(xs); - } -} /*******************************************************\ * Perform special action on behalf of the user * * Knows about the internals of this device * @@ -1146,7 +963,7 @@ caddr_t arg; \*******************************************************/ flags = 0; /* give error messages, act on errors etc. */ unit = UNIT(dev); - st = st_data + unit; + st = st_data[unit]; switch(cmd) { @@ -1173,9 +990,11 @@ caddr_t arg; { struct mtop *mt = (struct mtop *) arg; +#ifdef STDEBUG if (st_debug) printf("[sctape_sstatus: %x %x]\n", mt->mt_op, mt->mt_count); +#endif /*STDEBUG*/ @@ -1184,34 +1003,33 @@ caddr_t arg; switch ((short)(mt->mt_op)) { case MTWEOF: /* write an end-of-file record */ - if(!st_write_filemarks(unit,number,flags)) errcode = EIO; - st_data[unit].flags &= ~ST_WRITTEN; + errcode = st_write_filemarks(unit,number,flags); break; case MTFSF: /* forward space file */ - if(!st_space(unit,number,SP_FILEMARKS,flags)) errcode = EIO; + errcode = st_space(unit,number,SP_FILEMARKS,flags); break; case MTBSF: /* backward space file */ - if(!st_space(unit,-number,SP_FILEMARKS,flags)) errcode = EIO; + errcode = st_space(unit,-number,SP_FILEMARKS,flags); break; case MTFSR: /* forward space record */ - if(!st_space(unit,number,SP_BLKS,flags)) errcode = EIO; + errcode = st_space(unit,number,SP_BLKS,flags); break; case MTBSR: /* backward space record */ - if(!st_space(unit,-number,SP_BLKS,flags)) errcode = EIO; + errcode = st_space(unit,-number,SP_BLKS,flags); break; case MTREW: /* rewind */ - if(!st_rewind(unit,FALSE,flags)) errcode = EIO; + errcode = st_rewind(unit,FALSE,flags); break; case MTOFFL: /* rewind and put the drive offline */ if(st_rewind(unit,FALSE,flags)) { - st_prevent(unit,PR_ALLOW,0); - st_load(unit,LD_UNLOAD,flags); + printf("st%d: rewind failed, unit still loaded\n", + unit); } else { - printf("st%d: rewind failed, unit still loaded\n", - unit); + st_prevent(unit,PR_ALLOW,0); + st_load(unit,LD_UNLOAD,flags); } break; case MTNOP: /* no operation, sets status only */ @@ -1219,33 +1037,23 @@ caddr_t arg; case MTNOCACHE: /* disable controller cache */ break; case MTSETBSIZ: /* Set block size for device */ - if (st->blkmin == st->blkmax) + if (st->blkmin && st->blkmin == st->blkmax || + st->quirks & ST_Q_FORCE_FIXED_MODE) + /* Per definition in mtio.h, this is a */ + /* no-op for a real fixed block device */ + break; + if (!(st->flags & ST_AT_BOM) || number < 0 || number > 0 + && (number < st->blkmin || number > st->blkmax)) { - /* This doesn't make sense for a */ - /* real fixed block device */ errcode = EINVAL; - } + break; + } + if (number == 0) + st->flags &= ~ST_FIXEDBLOCKS; else - { - if ( number == 0 ) - { - /* Restoring original block size */ - st->flags &= ~ST_FIXEDBLOCKS; /*XXX*/ - st->blksiz = st->media_blksiz; - } - else - { - if (number < st->blkmin || number > st->blkmax) - { - errcode = EINVAL; - } - else - { - st->blksiz = number; - st->flags |= ST_FIXEDBLOCKS; - } - } - } + st->flags |= ST_FIXEDBLOCKS; + st->blksiz = number; + st->flags |= ST_BLOCK_SET; break; /* How do we check that the drive can handle @@ -1299,35 +1107,49 @@ caddr_t arg; return errcode; } - -#ifdef removing_this /*******************************************************\ -* Check with the device that it is ok, (via scsi driver)* +* Do a synchronous read. * \*******************************************************/ -st_req_sense(unit, flags) -int flags; +int st_read(unit, buf, size, flags) +int unit, size, flags; +char *buf; { - struct scsi_sense_data sense; - struct scsi_sense scsi_cmd; + int error; + struct scsi_rw_tape scsi_cmd; + struct st_data *st = st_data[unit]; - bzero(&scsi_cmd, sizeof(scsi_cmd)); - scsi_cmd.op_code = REQUEST_SENSE; - scsi_cmd.length = sizeof(sense); + /*******************************************************\ + * If it's a null transfer, return immediatly * + \*******************************************************/ + if (size == 0) + { + return(ESUCCESS); + } - if (st_scsi_cmd(unit, + /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && (error = st_decide_mode(unit, TRUE))) + return (error); + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + scsi_cmd.op_code = READ_COMMAND_TAPE; + scsi_cmd.byte2 |= st->flags & ST_FIXEDBLOCKS ? SRWT_FIXED : 0; + lto3b(scsi_cmd.byte2 & SRWT_FIXED ? + size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE) : size, + scsi_cmd.len); + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), - &sense, - sizeof(sense), + buf, + size, 100000, - flags | SCSI_DATA_IN) != 0) - { - return(FALSE); - } - return(TRUE); + NULL, + flags | SCSI_DATA_IN)); } -#endif /*******************************************************\ * Get scsi driver to send a "are you ready" command * \*******************************************************/ @@ -1339,17 +1161,14 @@ int unit,flags; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = TEST_UNIT_READY; - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 100000, - flags) != 0) - { - return(FALSE); - } - return(TRUE); + NULL, + flags)); } @@ -1367,11 +1186,13 @@ int unit,flags; { struct scsi_blk_limits scsi_cmd; struct scsi_blk_limits_data scsi_blkl; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; + int errno; + /*******************************************************\ * First check if we have it all loaded * \*******************************************************/ - if ((st->flags & ST_INFO_VALID)) return TRUE; + if ((st->flags & ST_INFO_VALID)) return 0; /*******************************************************\ * do a 'Read Block Limits' * @@ -1382,26 +1203,27 @@ int unit,flags; /*******************************************************\ * do the command, update the global values * \*******************************************************/ - if (st_scsi_cmd(unit, + if ( errno = st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), &scsi_blkl, sizeof(scsi_blkl), 5000, - flags | SCSI_DATA_IN) != 0) + NULL, + flags | SCSI_DATA_IN)) { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not get blk limits\n", unit); - st->flags &= ~ST_INFO_VALID; - return(FALSE); + return errno; } st->blkmin = b2tol(scsi_blkl.min_length); st->blkmax = _3btol(&scsi_blkl.max_length_2); +#ifdef STDEBUG if (st_debug) { - printf(" (%d <= blksiz <= %d\n) ",st->blkmin,st->blkmax); + printf("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax); } +#endif /*STDEBUG*/ + return 0; } /*******************************************************\ @@ -1418,6 +1240,7 @@ st_mode_sense(unit, flags) int unit,flags; { int scsi_sense_len; + int errno; char *scsi_sense_ptr; struct scsi_mode_sense scsi_cmd; struct scsi_sense @@ -1438,12 +1261,12 @@ int unit,flags; /* They also expect page 00 */ /* back when you issue a mode select */ }scsi_sense_page_0; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; /*******************************************************\ * First check if we have it all loaded * \*******************************************************/ - if ((st->flags & ST_INFO_VALID)) return(TRUE); + if ((st->flags & ST_INFO_VALID)) return 0; /*******************************************************\ * Define what sort of structure we're working with * @@ -1472,51 +1295,49 @@ int unit,flags; * or if we need it as a template for the mode select * * store it away. * \*******************************************************/ - if (st_scsi_cmd(unit, + if (errno = st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), scsi_sense_ptr, scsi_sense_len, 5000, - flags | SCSI_DATA_IN) != 0) + NULL, + flags | SCSI_DATA_IN) ) { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not mode sense\n", unit); - st->flags &= ~ST_INFO_VALID; - return(FALSE); + return errno; } st->numblks = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks)); st->media_blksiz = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen)); st->media_density = ((struct scsi_sense *)scsi_sense_ptr)->blk_desc.density; + if (((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec & + SMH_DSP_WRITE_PROT) + st->flags |= ST_READONLY; +#ifdef STDEBUG if (st_debug) { - printf("unit %d: %d blocks of %d bytes, write %s, %sbuffered", - unit, - st->numblks, - st->media_blksiz, - ((((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec - & SMH_DSP_WRITE_PROT) ? - "protected" : "enabled"), - ((((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec - & SMH_DSP_BUFF_MODE)? - "" : "un") - ); + printf("st%d: density code 0x%x, %d-byte blocks, write-%s, ", + unit, st->media_density, st->media_blksiz, + st->flags & ST_READONLY ? "protected" : "enabled"); + printf("%sbuffered\n", + ((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec + & SMH_DSP_BUFF_MODE ? "" : "un"); } +#endif /*STDEBUG*/ if (st->quirks & ST_Q_NEEDS_PAGE_0) { bcopy(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data, st->sense_data, sizeof(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data)); } - return(TRUE); + return 0; } /*******************************************************\ * Send a filled out parameter structure to the drive to * * set it into the desire modes etc. * \*******************************************************/ -st_mode_select(unit, flags, dsty_code) -int unit,flags,dsty_code; +st_mode_select(unit, flags) +int unit, flags; { int dat_len; char *dat_ptr; @@ -1532,7 +1353,7 @@ int unit,flags,dsty_code; struct blk_desc blk_desc; unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE]; }dat_page_0; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; /*******************************************************\ * Define what sort of structure we're working with * @@ -1557,7 +1378,7 @@ int unit,flags,dsty_code; scsi_cmd.length = dat_len; ((struct dat *)dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc); ((struct dat *)dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON; - ((struct dat *)dat_ptr)->blk_desc.density = dsty_code; + ((struct dat *)dat_ptr)->blk_desc.density = st->density; if(st->flags & ST_FIXEDBLOCKS) { lto3b( st->blksiz , ((struct dat *)dat_ptr)->blk_desc.blklen); @@ -1572,20 +1393,14 @@ int unit,flags,dsty_code; /*******************************************************\ * do the command * \*******************************************************/ - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), dat_ptr, dat_len, 5000, - flags | SCSI_DATA_OUT) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not mode select\n", unit); - st->flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags | SCSI_DATA_OUT) ); } /*******************************************************\ @@ -1594,28 +1409,33 @@ int unit,flags,dsty_code; st_space(unit,number,what,flags) int unit,number,what,flags; { + int error; struct scsi_space scsi_cmd; + struct st_data *st = st_data[unit]; + + /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && + (error = st_decide_mode(unit, TRUE))) + return (error); /* if we are at a filemark now, we soon won't be*/ - st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + st->flags &= ~ST_PER_ACTION; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = SPACE; scsi_cmd.byte2 = what & SS_CODE; lto3b(number,scsi_cmd.number); - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 600000, /* 10 mins enough? */ - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not space\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags)); } /*******************************************************\ * write N filemarks * @@ -1623,57 +1443,67 @@ int unit,number,what,flags; st_write_filemarks(unit,number,flags) int unit,number,flags; { + int error; struct scsi_write_filemarks scsi_cmd; + struct st_data *st = st_data[unit]; + + /*******************************************************\ + * It's hard to write a negative number of file marks. * + * Don't try. * + \*******************************************************/ + if (number < 0) + return (EINVAL); - st_data[unit].flags &= ~(ST_AT_FILEMARK); + /*******************************************************\ + * If we're at beginning of medium, now is the time to * + * set medium access density, fixed or variable-blocks * + * and, if fixed, the block size. * + \*******************************************************/ + if (st->flags & ST_AT_BOM && + (error = st_decide_mode(unit, FALSE))) + return (error); + + st->flags &= ~(ST_AT_FILEMARK | ST_WRITTEN); bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = WRITE_FILEMARKS; lto3b(number,scsi_cmd.number); - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 100000, /* 10 secs.. (may need to repos head )*/ - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not write_filemarks\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags) ); } /*******************************************************\ -* load /unload (with retension if true) * +* load/unload (with retension if true) * \*******************************************************/ st_load(unit,type,flags) int unit,type,flags; { struct scsi_load scsi_cmd; + struct st_data *st = st_data[unit]; - st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + st->flags &= ~ST_PER_ACTION; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = LOAD_UNLOAD; scsi_cmd.how=type; if (type == LD_LOAD) { /*scsi_cmd.how |= LD_RETEN;*/ + st->flags |= ST_AT_BOM; } - if (st_scsi_cmd(unit, + else + st->flags &= ~ST_INFO_VALID; + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, - 30000, /* 30 secs */ - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("cannot load/unload st%d\n", unit); - return(FALSE); - st_data[unit].flags &= ~ST_INFO_VALID; - } - return(TRUE); + 300000, /* 5 min */ + NULL, + flags)); } /*******************************************************\ * Prevent or allow the user to remove the tape * @@ -1683,23 +1513,19 @@ int unit,type,flags; { struct scsi_prevent scsi_cmd; + if (type == PR_ALLOW) + st_data[unit]->flags &= ~ST_INFO_VALID; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = PREVENT_ALLOW; scsi_cmd.how=type; - if (st_scsi_cmd(unit, + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, 5000, - flags) != 0) - { - if(!(flags & SCSI_SILENT)) - printf("st%d: cannot prevent/allow\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); - } - return(TRUE); + NULL, + flags)); } /*******************************************************\ * Rewind the device * @@ -1708,26 +1534,330 @@ st_rewind(unit,immed,flags) int unit,immed,flags; { struct scsi_rewind scsi_cmd; + struct st_data *st = st_data[unit]; - st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM); + st->flags &= ~ST_PER_ACTION; + st->flags |= ST_AT_BOM; bzero(&scsi_cmd, sizeof(scsi_cmd)); scsi_cmd.op_code = REWIND; - scsi_cmd.byte2=immed?SR_IMMED:0?SR_IMMED:0; - if (st_scsi_cmd(unit, + scsi_cmd.byte2 = immed ? SR_IMMED : 0; + return (st_scsi_cmd(unit, &scsi_cmd, sizeof(scsi_cmd), 0, 0, immed?5000:300000, /* 5 sec or 5 min */ - flags) != 0) + NULL, + flags)); +} + +/***************************************************************\ +* ststart 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 st_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 (ststrategy) * +* * +* 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. * +\***************************************************************/ +/* ststart() is called at splbio */ +ststart(unit) +{ + int drivecount; + register struct buf *bp = 0; + register struct buf *dp; + struct scsi_rw_tape cmd; + int blkno, nblk; + struct st_data *st = st_data[unit]; + int flags; + + + +#ifdef STDEBUG + if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit); +#endif /*STDEBUG*/ + /*******************************************************\ + * See if there is a buf to do and we are not already * + * doing one * + \*******************************************************/ + if(st->scsi_xfer.flags & INUSE) + { + return; /* unit already underway */ + } +trynext: + if(st->xfer_block_wait) /* a special awaits, let it proceed first */ + { + wakeup(&(st->xfer_block_wait)); + return; + } + + if ((bp = st->buf_queue) == NULL) + { + return; /* no work to bother with */ + } + st->buf_queue = bp->b_actf; + + + + /*******************************************************\ + * only FIXEDBLOCK devices have pending operations * + \*******************************************************/ + if(st->flags & ST_FIXEDBLOCKS) + { + /*******************************************************\ + * If we are at a filemark but have not reported it yet * + * then we should report it now * + \*******************************************************/ + if(st->flags & ST_AT_FILEMARK) + { + bp->b_resid = bp->b_bcount; + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + st->flags &= ~ST_AT_FILEMARK; + biodone(bp); + goto trynext; + } + /*******************************************************\ + * If we are at EIO (e.g. EOM) but have not reported it * + * yet then we should report it now * + \*******************************************************/ + if(st->flags & ST_EIO_PENDING) + { + bp->b_resid = bp->b_bcount; + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + st->flags &= ~ST_EIO_PENDING; + biodone(bp); + goto trynext; + } + } + /*******************************************************\ + * Fill out the scsi command * + \*******************************************************/ + bzero(&cmd, sizeof(cmd)); + if((bp->b_flags & B_READ) == B_WRITE) + { + cmd.op_code = WRITE_COMMAND_TAPE; + st->flags |= ST_WRITTEN; + flags = SCSI_DATA_OUT; + } + else + { + cmd.op_code = READ_COMMAND_TAPE; + flags = SCSI_DATA_IN; + } + + /*******************************************************\ + * Handle "fixed-block-mode" tape drives by using the * + * block count instead of the length. * + \*******************************************************/ + if(st->flags & ST_FIXEDBLOCKS) { - if(!(flags & SCSI_SILENT)) - printf("st%d: could not rewind\n", unit); - st_data[unit].flags &= ~ST_INFO_VALID; - return(FALSE); + cmd.byte2 |= SRWT_FIXED; + lto3b(bp->b_bcount/st->blksiz,cmd.len); } - return(TRUE); + else + { + lto3b(bp->b_bcount,cmd.len); + } + + /*******************************************************\ + * go ask the adapter to do all this for us * + \*******************************************************/ + if (st_scsi_cmd(unit, + &cmd, + sizeof(cmd), + (u_char *)bp->b_un.b_addr, + bp->b_bcount, + 100000, + bp, + flags | SCSI_NOSLEEP ) != SUCCESSFULLY_QUEUED) + + { + printf("st%d: oops not queued\n",unit); + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + biodone(bp); + return; + } + stqueues++; +} + +/*******************************************************\ +* This routine is called by the scsi interrupt when * +* the transfer is complete. +\*******************************************************/ +int st_done(unit,xs) +int unit; +struct scsi_xfer *xs; +{ + struct buf *bp; + int retval; + struct st_data *st = st_data[unit]; + +#ifdef STDEBUG + if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit); +#endif /*STDEBUG*/ +#ifdef PARANOID + if (! (xs->flags & INUSE)) + panic("scsi_xfer not in use!"); +#endif /*PARANOID*/ + if((bp = xs->bp)== NULL) + { + wakeup(xs); + return; + } + switch(xs->error) + { + case XS_NOERROR: + bp->b_flags &= ~B_ERROR; + bp->b_error = 0; + bp->b_resid = 0; + break; + case XS_SENSE: + retval = (st_interpret_sense(unit,xs)); + bp->b_resid = xs->resid; /* already multiplied by blksiz */ + if(retval) + { + /***************************************\ + * We have a real error, the bit should * + * be set to indicate this. The return * + * value will contain the unix error code* + * that the error interpretation routine * + * thought was suitable, so pass this * + * value back in the buf structure. * + * Furthermore we return information * + * saying that no data was transferred * + * All status is now suspect * + \***************************************/ + bp->b_flags |= B_ERROR; + bp->b_error = retval; + bp->b_resid = bp->b_bcount; + st->flags &= ~ST_PER_ACTION; + } + else + { + /***********************************************\ + * The error interpretation code has declared * + * that it wasn't a real error, or at least that * + * we should be ignoring it if it was. * + \***********************************************/ + if(xs->resid == 0) + { + /***************************************\ + * we apparently had a corrected error * + * or something. * + * pretend the error never happenned * + \***************************************/ + bp->b_flags &= ~B_ERROR; + bp->b_error = 0; + break; + } + if ( xs->resid != xs->datalen ) + { + /***************************************\ + * Here we have the tricky part.. * + * We successfully read less data than * + * we requested. (but not 0) * + *------for variable blocksize tapes:----* + * UNDER 386BSD: * + * We should legitimatly have the error * + * bit set, with the error value set to * + * zero.. This is to indicate to the * + * physio code that while we didn't get * + * as much information as was requested, * + * we did reach the end of the record * + * and so physio should not call us * + * again for more data... we have it all * + * SO SET THE ERROR BIT! * + * * + * UNDER NetBSD: * + * To indicate the same as above, we * + * need only have a non 0 resid that is * + * less than the b_bcount, but the * + * ERROR BIT MUST BE CLEAR! (sigh) * + * * + *-------for fixed blocksize device------* + * We read some successful records * + * before hitting the EOF or EOT. These * + * must be passed to the user, before we * + * report the EOx. We will report the * + * EOx NEXT time. * + \***************************************/ +#ifdef NETBSD + bp->b_flags &= ~B_ERROR; +#else + bp->b_flags |= B_ERROR; +#endif + bp->b_error = 0; + xs->error = XS_NOERROR; + break; + } + else + { + /***************************************\ + * We have come out of the error handler * + * with no error code. We have also not * + * transferred any data (would have gone * + * to the previous clause). * + * This must be an EOF * + * Any caller request to read no * + * data would have been short-circuited * + * at st_read or ststrategy. * + * * + * At least all o/s agree that: * + * 0 bytes read with no error is EOF * + \***************************************/ + + bp->b_error = 0; + bp->b_flags &= ~B_ERROR; + st->flags &= ~ST_AT_FILEMARK; + break; + } + } + break; + + case XS_TIMEOUT: + printf("st%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->flags &= ~ITSDONE; + xs->error = XS_NOERROR; + if ( (*(st->sc_sw->scsi_cmd))(xs) + == SUCCESSFULLY_QUEUED) + { /* don't wake the job, ok? */ + return; + } + printf("st%d: device busy\n",unit); + xs->flags |= ITSDONE; + } + + case XS_DRIVER_STUFFUP: + bp->b_flags |= B_ERROR; + bp->b_error = EIO; + break; + default: + printf("st%d: unknown error category from scsi driver\n" + ,unit); + } + biodone(bp); + xs->flags = 0; /* no longer in use */ + ststart(unit); /* If there's another waiting.. do it */ } + + + /*******************************************************\ * ask the scsi driver to perform a command for us. * * Call it through the switch table, and tell it which * @@ -1737,115 +1867,120 @@ int unit,immed,flags; * Also tell it where to read/write the data, and how * * long the data is supposed to be * \*******************************************************/ -int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags) +int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags) int unit,flags; struct scsi_generic *scsi_cmd; int cmdlen; int timeout; u_char *data_addr; +struct buf *bp; int datalen; { struct scsi_xfer *xs; int retval; int s; - struct st_data *st = st_data + unit; + struct st_data *st = st_data[unit]; +#ifdef STDEBUG if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit); - if(st->sc_sw) /* If we have a scsi driver */ +#endif /*STDEBUG*/ +#ifdef PARANOID + if(st->sc_sw == NULL) /* If we have no scsi driver */ { + printf("st%d: not set up\n",unit); + return(EINVAL); + } +#endif /*PARANOID*/ - xs = &(st_scsi_xfer[unit]); - if(!(flags & SCSI_NOMASK)) - s = splbio(); - st_xfer_block_wait[unit]++; /* there is someone waiting */ - while (xs->flags & INUSE) - { - sleep(&st_xfer_block_wait[unit],PRIBIO+1); - } - st_xfer_block_wait[unit]--; - xs->flags = INUSE; - if(!(flags & SCSI_NOMASK)) - splx(s); + xs = &(st->scsi_xfer); + if(!(flags & SCSI_NOMASK)) + s = splbio(); + st->xfer_block_wait++; /* there is someone waiting */ + while (xs->flags & INUSE) + { + if(flags & SCSI_NOSLEEP) + return EBUSY; + sleep(&(st->xfer_block_wait),PRIBIO+1); + } + st->xfer_block_wait--; + xs->flags = INUSE; + if(!(flags & SCSI_NOMASK)) + splx(s); - /*******************************************************\ - * Fill out the scsi_xfer structure * - \*******************************************************/ - xs->flags |= flags; - xs->adapter = st->ctlr; - xs->targ = st->targ; - xs->lu = st->lu; - xs->retries = ST_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 - :st_done; - xs->done_arg = unit; - xs->done_arg2 = (int)xs; -retry: xs->error = XS_NOERROR; - xs->bp = 0; - retval = (*(st->sc_sw->scsi_cmd))(xs); - switch(retval) + /*******************************************************\ + * Fill out the scsi_xfer structure * + \*******************************************************/ + xs->flags |= flags; + xs->adapter = st->ctlr; + xs->targ = st->targ; + xs->lu = st->lu; + xs->retries = bp?0:ST_RETRIES;/*can't retry on IO*/ + xs->timeout = timeout; + xs->cmd = scsi_cmd; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->resid = datalen; + xs->when_done = st_done; + xs->done_arg = unit; + xs->done_arg2 = (int)xs; + xs->bp = bp; +retry: xs->error = XS_NOERROR; + + /***********************************************\ + * Ask the adapter to do the command for us * + \***********************************************/ + retval = (*(st->sc_sw->scsi_cmd))(xs); + + /***********************************************\ + * IO operations are handled differently.. * + * Physio does the sleep, and error handling is * + * Done in st_done at interrupt time * + \***********************************************/ + if(bp) return retval; + + /***********************************************\ + * Wait for the result if queued, or handle the * + * error if it was rejected.. * + \***********************************************/ + switch(retval) + { + case SUCCESSFULLY_QUEUED: + s = splbio(); + while(!(xs->flags & ITSDONE)) + sleep(xs,PRIBIO+1); + splx(s); + /*******************************\ + * finished.. check for failure * + * Fall through...... * + \*******************************/ + case HAD_ERROR: + case COMPLETE: + switch(xs->error) { - case SUCCESSFULLY_QUEUED: - s = splbio(); - while(!(xs->flags & ITSDONE)) - sleep(xs,PRIBIO+1); - splx(s); - - case HAD_ERROR: - case COMPLETE: - switch(xs->error) + case XS_NOERROR: + retval = ESUCCESS; + break; + case XS_SENSE: + retval = (st_interpret_sense(unit,xs)); + /* only useful for reads *//* why did I say that?*/ + if (retval) + { /* error... don't care about filemarks */ + st->flags &= ~ST_PER_ACTION; + } + else { - case XS_NOERROR: + xs->error = XS_NOERROR; retval = ESUCCESS; - break; - case XS_SENSE: - retval = (st_interpret_sense(unit,xs)); - /* only useful for reads */ - if (retval) - { /* error... don't care about filemarks */ - st->flags &= ~(ST_AT_FILEMARK - | ST_AT_EOM); - } - else - { - xs->error = XS_NOERROR; - retval = ESUCCESS; - } - 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("st%d: unknown error category from scsi driver\n" - ,unit); - break; - } + } break; - case TRY_AGAIN_LATER: + case XS_DRIVER_STUFFUP: + retval = EIO; + break; + case XS_BUSY: + /* should sleep 1 sec here */ + case XS_TIMEOUT: if(xs->retries-- ) { xs->flags &= ~ITSDONE; @@ -1855,15 +1990,25 @@ retry: xs->error = XS_NOERROR; break; default: retval = EIO; + printf("st%d: unknown error category from scsi driver\n" + ,unit); + break; + } + break; + case TRY_AGAIN_LATER: + if(xs->retries-- ) + { + xs->flags &= ~ITSDONE; + /* should delay here */ + goto retry; } - xs->flags = 0; /* it's free! */ - ststart(unit); - } - else - { - printf("st%d: not set up\n",unit); - return(EINVAL); + retval = EIO; + break; + default: + retval = EIO; } + xs->flags = 0; /* it's free! */ + ststart(unit); return(retval); } /***************************************************************\ @@ -1878,6 +2023,9 @@ struct scsi_xfer *xs; struct scsi_sense_data *sense; int key; int silent = xs->flags & SCSI_SILENT; + struct st_data *st = st_data[unit]; + int info; + int errno = 0;/* default error */ /***************************************************************\ * If errors are ok, report a success * @@ -1885,9 +2033,10 @@ struct scsi_xfer *xs; if(xs->flags & SCSI_ERR_OK) return(ESUCCESS); /***************************************************************\ - * Get the sense fields and work out what CLASS * + * Get the sense fields and work out what code * \***************************************************************/ sense = &(xs->sense); +#ifdef STDEBUG if(st_debug) { int count = 0; @@ -1913,51 +2062,98 @@ struct scsi_xfer *xs; } printf("\n"); } +#endif /*STDEBUG*/ + if(sense->error_code & SSD_ERRCODE_VALID) + { + info = ntohl(*((long *)sense->ext.extended.info)); + } + else + { + info = xs->datalen; /* bad choice if fixed blocks */ + } + + switch(sense->error_code & SSD_ERRCODE) { /***************************************************************\ - * If it's class 7, use the extended stuff and interpret the key * + * If it's code 70, use the extended stuff and interpret the key * \***************************************************************/ case 0x70: { - if(sense->ext.extended.flags & SSD_EOM) + if(st->flags & ST_FIXEDBLOCKS) { - st_data[unit].flags |= ST_AT_EOM; - } + xs->resid = info * st->blksiz; + if(sense->ext.extended.flags & SSD_EOM) + { + st->flags |= ST_EIO_PENDING; + } + if(sense->ext.extended.flags & SSD_FILEMARK) + { + st->flags |= ST_AT_FILEMARK; + } + if(sense->ext.extended.flags & SSD_ILI) + { + st->flags |= ST_EIO_PENDING; + /*******************************************************\ + * The following quirk code deals with the fact that the * + * value of media_blksiz returned by the drive in * + * response to an st_mode_sense call doesn't reflect the * + * tape's format. * + * * + * The method is to try a fixed-length block read and * + * let this code determine whether the tape has fixed or * + * variable-length blocks, by seeing if we get an ILI * + * * + * Since the quirk code is the only place that calls the * + * board without the INFO_VALID set, catch that case * + * and handle it here (no other way of catching it * + * because resid info can't get passed without a buf) * + \*******************************************************/ - if(sense->ext.extended.flags & SSD_FILEMARK) - { - st_data[unit].flags |= ST_AT_FILEMARK; + if ((st->quirks & ST_Q_SNS_HLP) + && !(st->flags & ST_INFO_VALID)) + { + st->blksiz = 0; + } + } + /***********************************************\ + * If no data was tranfered, do it immediatly * + \***********************************************/ + if(xs->resid == xs->datalen) + { + if(st->flags & ST_EIO_PENDING) + { + return EIO; + } + if(st->flags & ST_AT_FILEMARK) + { + return 0; + } + } } - - if(sense->ext.extended.flags & SSD_ILI) + else { - if(sense->error_code & SSD_ERRCODE_VALID) + xs->resid = xs->datalen; /* to be sure */ + if(sense->ext.extended.flags & SSD_EOM) { - /*******************************\ - * In all ili cases, note that * - * the resid is non-0 AND not * - * unchanged. * - \*******************************/ - xs->resid - = ntohl(*((long *)sense->ext.extended.info)); - if(xs->bp) - { - if(xs->resid < 0) - { /* never on block devices */ - /***********************\ - * it's only really bad * - * if we have lost data * - * (the record was * - * bigger than the read) * - \***********************/ - return(EIO); - } - } + return(EIO); } - else - { /* makes no sense.. complain */ - printf("st%d: BAD length error?\n", unit); + if(sense->ext.extended.flags & SSD_FILEMARK) + { + return 0; + } + if(sense->ext.extended.flags & SSD_ILI) + { + if(info < 0) + /***************************************\ + * the record was bigger than the read * + \***************************************/ + { + printf("st%d: record of %d bytes too big\n", + unit, xs->datalen - info); + return(EIO); + } + xs->resid = info; } }/* there may be some other error. check the rest */ @@ -1965,25 +2161,20 @@ struct scsi_xfer *xs; switch(key) { case 0x0: - if(!(sense->ext.extended.flags & SSD_ILI)) - xs->resid = 0; /* XXX check this */ + if(xs->resid == xs->datalen) xs->resid = 0; return(ESUCCESS); case 0x1: + if(xs->resid == xs->datalen) xs->resid = 0; if(!silent) { - printf("st%d: soft error(corrected) ", unit); + printf("st%d: soft error(corrected)", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf("info = %d (decimal)", + info); } printf("\n"); } - if(!(sense->ext.extended.flags & SSD_ILI)) - xs->resid = 0; /* XXX check this */ return(ESUCCESS); case 0x2: if(!silent) printf("st%d: not ready\n", unit); @@ -1991,14 +2182,11 @@ struct scsi_xfer *xs; case 0x3: if(!silent) { - printf("st%d: medium error ", unit); + printf("st%d: medium error", unit); if(sense->error_code & SSD_ERRCODE_VALID) { - printf("block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + printf(" block no. %d (decimal)", + info); } printf("\n"); } @@ -2011,53 +2199,37 @@ struct scsi_xfer *xs; if(!silent) printf("st%d: illegal request\n", unit); return(EINVAL); case 0x6: - if(!silent) printf("st%d: Unit attention.\n", unit); - st_data[unit].flags &= ~(ST_AT_FILEMARK|ST_AT_EOM); - st_data[unit].flags &= ~ST_INFO_VALID; - if (st_data[unit].flags & ST_OPEN) /* TEMP!!!! */ + if(!silent) printf("st%d: Unit attention\n", unit); + st->flags &= ~ST_PER_MEDIA; + if (st->flags & ST_OPEN) /* TEMP!!!! */ return(EIO); else return(ESUCCESS); case 0x7: if(!silent) - { - printf("st%d: attempted protection violation", - unit); - if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); - } - printf("\n"); - } + printf("st%d: tape is write protected\n", unit); return(EACCES); case 0x8: if(!silent) { - printf("st%d: fixed block wrong size", - unit); + printf("st%d: no data found", unit); if(sense->error_code & SSD_ERRCODE_VALID) - { - printf(" requested size: %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(": requested size: %d (decimal)", + info); printf("\n"); } return(EIO); case 0x9: - if(!silent) printf("st%d: vendor unique\n", unit); + if(!silent) printf("st%d: vendor unique\n", + unit); return(EIO); case 0xa: - if(!silent) printf("st%d: copy aborted\n", unit); + if(!silent) printf("st%d: copy aborted\n", + unit); return(EIO); case 0xb: - if(!silent) printf("st%d: command aborted\n", unit); + if(!silent) printf("st%d: command aborted\n", + unit); return(EIO); case 0xc: if(!silent) @@ -2066,16 +2238,14 @@ struct scsi_xfer *xs; if(sense->error_code & SSD_ERRCODE_VALID) { printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + info); } printf("\n"); } return(ESUCCESS); case 0xd: - if(!silent) printf("st%d: volume overflow\n ", unit); + if(!silent) printf("st%d: volume overflow\n", + unit); return(ENOSPC); case 0xe: if(!silent) @@ -2084,22 +2254,20 @@ struct scsi_xfer *xs; if(sense->error_code & SSD_ERRCODE_VALID) { printf(" block no. %d (decimal)", - (sense->ext.extended.info[0] <<24)| - (sense->ext.extended.info[1] <<16)| - (sense->ext.extended.info[2] <<8)| - (sense->ext.extended.info[3] )); + info); } printf("\n"); } return(EIO); case 0xf: - if(!silent) printf("st%d: unknown error key\n", unit); + if(!silent) printf("st%d: unknown error key\n", + unit); return(EIO); } break; } /***************************************************************\ - * If it's NOT class 7, just report it. * + * If it's NOT code 70, just report it. * \***************************************************************/ default: { @@ -2121,20 +2289,3 @@ struct scsi_xfer *xs; return(EIO); } } - -#if defined(OSF) - -stsize(dev_t dev) -{ - printf("stsize() -- not implemented\n"); - return(0); -} - -stdump() -{ - printf("stdump() -- not implemented\n"); - return(-1); -} - -#endif /* defined(OSF) */ - |