Return to BSD News archive
Newsgroups: comp.unix.bsd Path: sserve!manuel!munnari.oz.au!network.ucsd.edu!sdd.hp.com!uakari.primate.wisc.edu!ames!agate!tfs.com!tfs.com!julian From: julian@tfs.com (Julian Elischer) Subject: New scsi system beta3 (part 2 of 10) Message-ID: <1992Oct3.035907.13074@tfs.com> Organization: TRW Financial Systems Date: Sat, 3 Oct 1992 03:59:07 GMT Lines: 1310 # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # scsi # scsi/README # scsi/scsiconf.h # scsi/scsiconf.c # scsi/scsi_all.h # echo c - scsi mkdir scsi > /dev/null 2>&1 echo x - scsi/README sed 's/^X//' >scsi/README << 'END-of-scsi/README' XThis release consists of the following files X(relative to the base of the kernel tree) X Xddb/db_command.c.patch Xkern/kern_subr.c.patch Xi386/isa/isa.h.patch Xi386/isa/clock.c.patch Xi386/i386/conf.c.patch Xi386/conf/SCSITEST Xi386/conf/devices.i386.patch Xi386/conf/files.i386.patch Xi386/conf/Makefile.i386.patch Xscsi Xscsi/README Xscsi/scsiconf.h Xscsi/scsiconf.c Xscsi/scsi_all.h Xscsi/scsi_disk.h Xscsi/scsi_tape.h Xscsi/scsi_cd.h Xscsi/st.c Xscsi/sd.c Xscsi/cd.c Xi386/isa/aha1542.c X/dev/MAKEDEV X XThe patch files do the following things: X X ddb/db_command.c.patch X kern/kern_subr.c.patch XThese move the strcmp function out of ddb to a more generic place Xso I can use it even if ddb is not configured in. X X i386/isa/isa.h.patch Xdefine ports needed for the adaptec board. X X i386/isa/clock.c.patch Xadd a calibrated spinwait that can be used before the clock interrupts Xcan be used. (i.e. in boot up) X X i386/i386/conf.c.patch Xadd cdevsw and bdevsw table entries for the scsi disk and tape devices. X X i386/conf/devices.i386.patch Xdefine an sd device so I can config it for swap X X i386/conf/files.i386.patch Xdefine the files we need to compile in for this scsi system. X X i386/conf/Makefile.i386.patch XThis Makefile knows how to make the vers.c program. This should Xbecome un-needed when the patch kit fixes this bug. X X /dev/MAKEDEV XA replacement MAKEDEV that knows about these devices. X X X---------------------------------------------------------------- XThis scsi system is designed to allow the re-use of top end drivers Xsuch as disk and tape drivers, with different scsi adapters. X XAs of writing this document, There are top end drivers working for: X---------------------------------------------------------------- Xgeneric scsi disk Xgeneric scsi tape Xcd-rom (tested for SUN cd-rom only) XAEG Character recognition devices * XCalera Character recognition devices * XKodak IL900 scanner * XExabyte tape changer device.** X---------------------------------------------------------------- X X XThere are also working bottom end drivers for: X---------------------------------------------------------------- Xadaptec 1542 (and 1742 in 1542 mode) Xbustec 742a ** X---------------------------------------------------------------- X X XWork is proceeding on the following bottom end drivers: X---------------------------------------------------------------- XFuture Domain (8 and 16 bit)**** hosler@tfs.com & rpr@oce.nl XWD7000**** terry@icarus.weber.edu Xseagate st01/st02**** overby@aspen.cray.com ? Xadaptec 174x *** me XUltrastore *** overby@aspen.cray.com & friend? X---------------------------------------------------------------- X* drivers not made public (proprietary.. proof that the concept works though) X** driver not yet released but working. X*** just a dream so far. X**** some amount more than just a dream so far. X X X################## Using the scsi system ################## X------------minor numbers--------------- XThis scsi system does not allocate minor numbers to devices depending Xon their SCSI IDs is any way. A devices minor number is dependant Xon the order in which it was found. Xe.g. the first tape found will become st0 (minor number 0) X the second found will become st1 (minor number 16) X the third will become st2 (minor 32) X etc. X XThese devices could be on the same scsi bus or different scsi busses. XThat would not change their minor numbers. X XIt is possible to run two different TYPES of scsi adapters at the Xsame time and have st0 on one and st1 on another. (for example) X XThere is a scheme supported in which scsi devices can be 'wired in' even Xif they are not present or powered on at probe time. (see scsiconf.c) X X--------------getting started------------ XIt should be possible to use the /dev entries for as0 as if they were X/dev entries for sd0 and the old as bootblocks should Xcontinue to work if you are using an adaptec 1542b. X X--------------making devices------------ XA changed version of /dev/MAKEDEV is supplied that Xcan be used to make devices sd[01234] and st[01234] X Xe.g. Xcd /dev Xsh MAKEDEV sd0 sd1 sd2 st0 st1 cd0 X X XThe tape devices are as follows: Xrst0 basic raw device, will rewind on close Xnrst0 will not rewind on close Xerst0 will rewind and EJECTon close Xnerst0 will not rewind and WILL eject (some devices may rewind anyhow) X X------------future enhancements-------------- XSome people have indicated that they would like to have the SCSI ID Xencoded into the minor number in some way, and Xthis may be supported at some timein the future, using Xminor numbers greater than 128. (or maybe a different major number) X XI will also be writing (probably) a generic scsi-error Xhandling routine that will be table driven, so that the routine can Xbe removed from each individual driver. With enough care, Xtwo similar devices with different error codes (quite common) could run Xthe same driver but use different error tables. X X--------------file layout------------------- XOriginally I had all scsi definitions in one file: scsi.h XI have since moved definitions of commands so that all Xdefinitions needed for a particular type of device are Xfound together in the include file of that name. XThis approximatly follows the layout of their definition Xin the SCSI-2 spec. XAs such they are: X Xscsi_all.h general commands for all devices --- CHAPTER 7 Xscsi-disk.h commands relevant to disk --- CHAPTER 8 Xscsi-tape.h commands for scsi tapes --- CHAPTER 9 Xscsi-cd.h commands for cd-roms (and audio) --- CHAPTER 13 X X-----------cd-rom----------------- XI have only recntly added the cd-rom driver XI have mounted disk using the iso9660 file system Xbut have not managed to get the AUDIO commands to work (yet) XI have only tested this code on a SUN cd-rom which uses Xa 512 byte logical blocksize, however it has code to addapt Xto other logical blocksizes (multiples of 512 please!) X END-of-scsi/README echo x - scsi/scsiconf.h sed 's/^X//' >scsi/scsiconf.h << 'END-of-scsi/scsiconf.h' X/* X * Written by Julian Elischer (julian@tfs.com) X * for TRW Financial Systems for use under the MACH(2.5) operating system. X * X * TRW Financial Systems, in accordance with their agreement with Carnegie X * Mellon University, makes this software available to CMU to distribute X * or use in any manner that they see fit as long as this message is kept with X * the software. For this reason TFS also grants any other persons or X * organisations permission to use or modify this software. X * X * TFS supplies this software to be publicly redistributed X * on the understanding that TFS is not responsible for the correct X * functioning of this software in any circumstances. X * X */ X X/* X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 X */ X X/***********************************************\ X* these calls are called by the high-end * X* drivers to get services from whatever low-end * X* drivers they are attached to * X\***********************************************/ Xstruct scsi_switch X{ X int (*scsi_cmd)(); X void (*scsi_minphys)(); X int (*open_target_lu)(); X int (*close_target_lu)(); X long int (*adapter_info)(); /* see definitions below */ X u_long spare[3]; X}; X#define AD_INF_MAX_CMDS 0x000000FF /* maximum number of entries X queuable to a device by X the adapter */ X/* 24 bits of other adapter charcteristics go here */ X X/***********************************************\ X* The scsi debug control bits * X\***********************************************/ Xextern int scsi_debug; X#define PRINTROUTINES 0x01 X#define TRACEOPENS 0x02 X#define TRACEINTERRUPTS 0x04 X#define SHOWREQUESTS 0x08 X#define SHOWSCATGATH 0x10 X#define SHOWINQUIRY 0x20 X#define SHOWCOMMANDS 0x40 X X X/********************************/ X/* return values for scsi_cmd() */ X/********************************/ X#define SUCCESSFULLY_QUEUED 0 X#define TRY_AGAIN_LATER 1 X#define COMPLETE 2 X#define HAD_ERROR 3 X Xstruct scsi_xfer X{ X struct scsi_xfer *next; /* when free */ X int flags; X u_char adapter; X u_char targ; X u_char lu; X u_char retries; /* the number of times to retry */ X long int timeout; /* in miliseconds */ X struct scsi_generic *cmd; X int cmdlen; X u_char *data; /* either the dma address OR a uio address */ X int datalen; /* data len (blank if uio) */ X int resid; X int (*when_done)(); X int done_arg; X int done_arg2; X int error; X struct buf *bp; X struct scsi_sense_data sense; X}; X/********************************/ X/* Flag values */ X/********************************/ X#define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */ X#define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */ X#define SCSI_NOSTART 0x04 /* left over from ancient history */ X#define ITSDONE 0x10 /* the transfer is as done as it gets */ X#define INUSE 0x20 /* The scsi_xfer block is in use */ X#define SCSI_SILENT 0x40 /* Don't report errors to console */ X#define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */ X#define SCSI_RESET 0x100 /* Reset the device in question */ X#define SCSI_DATA_UIO 0x200 /* The data address refers to a UIO */ X#define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */ X#define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */ X/********************************/ X/* Error values */ X/********************************/ X#define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */ X#define XS_SENSE 0x1 /* Check the returned sense for the error */ X#define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */ X#define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */ X#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */ X#define XS_BUSY 0x08 /* The device busy, try again later? */ X END-of-scsi/scsiconf.h echo x - scsi/scsiconf.c sed 's/^X//' >scsi/scsiconf.c << 'END-of-scsi/scsiconf.c' X/* X * Written by Julian Elischer (julian@tfs.com) X * for TRW Financial Systems for use under the MACH(2.5) operating system. X * X * TRW Financial Systems, in accordance with their agreement with Carnegie X * Mellon University, makes this software available to CMU to distribute X * or use in any manner that they see fit as long as this message is kept with X * the software. For this reason TFS also grants any other persons or X * organisations permission to use or modify this software. X * X * TFS supplies this software to be publicly redistributed X * on the understanding that TFS is not responsible for the correct X * functioning of this software in any circumstances. X * X */ X X/* X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 X */ X X/* X$Log: X* X*/ X#include <sys/types.h> X#include "st.h" X#include "sd.h" X#include "ch.h" X#include "cd.h" X X#ifdef MACH X#include <i386/machparam.h> X#include <i386at/scsi_all.h> X#include <i386at/scsiconf.h> X#else MACH X#ifdef __386BSD__ X#include <scsi/scsi_all.h> X#include <scsi/scsiconf.h> X#endif __386BSD__ X#endif MACH X X#if !defined(OSF) && !defined(__386BSD__) X#include "bll.h" X#include "cals.h" X#endif /* !defined(OSF) && !defined(__386BSD__) */ X X#if NSD > 0 Xextern sdattach(); X#endif NSD X#if NST > 0 Xextern stattach(); X#endif NST X#if NCH > 0 Xextern chattach(); X#endif NCH X#if NCD > 0 Xextern cdattach(); X#endif NCD X#if NBLL > 0 Xextern bllattach(); X#endif NBLL X#if NCALS > 0 Xextern calsattach(); X#endif NCALS X X/***************************************************************\ X* The structure of pre-configured devices that might be turned * X* off and therefore may not show up * X\***************************************************************/ Xstruct predefined X{ X u_char scsibus; X u_char dev; X u_char lu; X int (*attach_rtn)(); X char *devname; X} Xpd[] = X{ X#ifdef EXAMPLE_PREDEFINE X#if NSD > 0 X {0,0,0,sdattach,"sd"}, /* define a disk at scsibus=0 dev=0 lu=0 */ X#endif NSD X#endif EXAMPLE_PREDEFINE X {0,9,9} /*illegal dummy end entry */ X}; X X X/***************************************************************\ X* The structure of known drivers for autoconfiguration * X\***************************************************************/ Xstatic struct scsidevs X{ X int type; X int removable; X char *manufacturer; X char *model; X char *version; X int (*attach_rtn)(); X char *devname; X char showme; /* 1 show my comparisons during boot(debug) */ X} Xknowndevs[] = { X#if NSD > 0 X { T_DIRECT,T_FIXED,"standard","any","any",sdattach,"sd" }, X { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S ","B5A ",sdattach,"mx1",0 }, X#endif NSD X#if NST > 0 X { T_SEQUENTIAL,T_REMOV,"standard","any","any",stattach,"st" }, X#endif NST X#if NCALS > 0 X { T_PROCESSOR,T_FIXED,"standard","any","any",calsattach,"cals" }, X#endif NCALS X#if NCH > 0 X { T_CHANGER,T_REMOV,"standard","any","any",chattach,"ch" }, X#endif NCH X#if NCD > 0 X { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 ","3.1a",cdattach,"cd" }, X#endif NCD X#if NBLL > 0 X { T_PROCESSOR,T_FIXED,"AEG ","READER ","V1.0",bllattach,"bll" }, X#endif NBLL X{0} X}; X/***************************************************************\ X* Declarations * X\***************************************************************/ Xstruct predefined *scsi_get_predef(); Xstruct scsidevs *scsi_probedev(); Xstruct scsidevs *selectdev(); X X/* controls debug level within the scsi subsystem */ X/* see scsiconf.h for values */ Xint scsi_debug = 0x0; Xint scsibus = 0x0; /* This is the Nth scsibus */ X X/***************************************************************\ X* The routine called by the adapter boards to get all their * X* devices configured in. * X\***************************************************************/ Xscsi_attachdevs( unit, scsi_addr, scsi_switch) Xint unit,scsi_addr; Xstruct scsi_switch *scsi_switch; X{ X int targ,lun; X struct scsidevs *bestmatch = (struct scsidevs *)0; X struct predefined *predef; X X#ifdef KODAK_SCANNER X printf("waiting for scsi devices to settle\n"); X spinwait(1000 * 30); X#endif KODAK_SCANNER X targ = 0; X while(targ < 8) X { X if (targ == scsi_addr) X { X targ++; X continue; X } X lun = 0; X while(lun < 8) X { X predef = scsi_get_predef(scsibus,targ,lun); X bestmatch = scsi_probedev(unit,targ,lun,scsi_switch); X if((bestmatch) && (predef)) /* both exist */ X { X if(bestmatch->attach_rtn X != predef->attach_rtn) X { X printf("Clash in found/expected devices\n"); X printf("will link in FOUND\n"); X } X (*(bestmatch->attach_rtn))(unit, X targ, X lun, X scsi_switch); X } X if((bestmatch) && (!predef)) /* just FOUND */ X { X (*(bestmatch->attach_rtn))(unit, X targ, X lun, X scsi_switch); X } X if((!bestmatch) && (predef)) /* just predef */ X { X (*(predef->attach_rtn))(unit, X targ, X lun, X scsi_switch); X } X if((lun == 0) && (!bestmatch) && (!predef)) X { X break; /* nothing here, skip to next targ */ X } X lun++; X } X targ++; X } X scsibus++; /* next time we are on the NEXT scsi bus */ X} X X/***********************************************\ X* given a target and lu, check if there is a * X* predefined device for that address * X\***********************************************/ Xstruct predefined *scsi_get_predef(unit,target,lu) Xint unit,target,lu; X{ X int upto,numents; X X numents = (sizeof(pd)/sizeof(struct predefined)) - 1; X X for(upto = 0;upto < numents;upto++) X { X if(pd[upto].scsibus != unit) X continue; X if(pd[upto].dev != target) X continue; X if(pd[upto].lu != lu) X continue; X X printf(" dev%d,lu%d: %s - PRECONFIGURED -\n" X ,target X ,lu X ,pd[upto].devname); X return(&(pd[upto])); X } X return((struct predefined *)0); X} X X/***********************************************\ X* given a target and lu, ask the device what * X* it is, and find the correct driver table * X* entry. * X\***********************************************/ Xstruct scsidevs *scsi_probedev(unit,target,lu,scsi_switch) X Xstruct scsi_switch *scsi_switch; Xint unit,target,lu; X{ X char *dtype,*desc; X struct scsi_inquiry_data inqbuf; X int len,type,remov; X char manu[32]; X char model[32]; X char version[32]; X X bzero(&inqbuf,sizeof(inqbuf)); X /***********************************************\ X * Ask the device what it is * X \***********************************************/ X#ifdef DEBUG X if((target == 0) && (lu == 0)) X scsi_debug = 0xfff; X else X scsi_debug = 0; X#endif DEBUG X if(scsi_ready( unit, X target, X lu, X scsi_switch, X SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) X { X return(struct scsidevs *)0; X } X if(scsi_inquire(unit, X target, X lu, X scsi_switch, X &inqbuf, X SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE) X { X return(struct scsidevs *)0; X } X X /***********************************************\ X * note what BASIC type of device it is * X \***********************************************/ X if(scsi_debug & SHOWINQUIRY) X { X desc=(char *)&inqbuf; X printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n", X desc[0], desc[1], desc[2], desc[3], X desc[4], desc[5], desc[6], desc[7], X desc[8], desc[9], desc[10], desc[11], X desc[12]); X } X type = inqbuf.device_type; X remov = inqbuf.removable; X switch(type) X { X case T_DIRECT: X dtype="direct"; X break; X case T_SEQUENTIAL: X dtype="sequential"; X break; X case T_PRINTER: X dtype="printer"; X break; X case T_PROCESSOR: X dtype="processor"; X break; X case T_READONLY: X dtype="readonly"; X break; X case T_WORM: X dtype="worm"; X break; X case T_SCANNER: X dtype="scanner"; X break; X case T_OPTICAL: X dtype="optical"; X break; X case T_CHANGER: X dtype="changer"; X break; X case T_COMM: X dtype="communication"; X break; X default: X dtype="unknown"; X break; X } X /***********************************************\ X * Then if it's advanced enough, more detailed * X * information * X \***********************************************/ X if(inqbuf.ansii_version > 0) X { X if ((len = inqbuf.additional_length X + ( (char *)inqbuf.unused X - (char *)&inqbuf)) X > (sizeof(struct scsi_inquiry_data) - 1)) X len = sizeof(struct scsi_inquiry_data) - 1; X desc=inqbuf.vendor; X desc[len-(desc - (char *)&inqbuf)] = 0; X strncpy(manu,inqbuf.vendor,8);manu[8]=0; X strncpy(model,inqbuf.product,16);model[16]=0; X strncpy(version,inqbuf.revision,4);version[4]=0; X } X else X /***********************************************\ X * If not advanced enough, use default values * X \***********************************************/ X { X desc="early protocol device"; X strncpy(manu,"unknown",8); X strncpy(model,"unknown",16); X strncpy(version,"????",4); X } X printf(" dev%d,lu%d: type %d(%s),%s '%s%s%s' scsi%d\n" X ,target X ,lu X ,type X ,dtype X ,remov?"removable":"fixed" X ,manu X ,model X ,version X ,inqbuf.ansii_version X ); X /***********************************************\ X * Try make as good a match as possible with * X * available sub drivers * X \***********************************************/ X return(selectdev(unit,target,lu,&scsi_switch, X type,remov,manu,model,version)); X} X X/***********************************************\ X* Try make as good a match as possible with * X* available sub drivers * X\***********************************************/ Xstruct scsidevs X*selectdev(unit,target,lu,dvr_switch,type,remov,manu,model,rev) Xint unit,target,lu; Xstruct scsi_switch *dvr_switch; Xint type,remov; Xchar *manu,*model,*rev; X{ X int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1; X int count = 0; X int bestmatches; X struct scsidevs *bestmatch = (struct scsidevs *)0; X struct scsidevs *thisentry = knowndevs; X X thisentry--; X while( count++ < numents) X { X thisentry++; X if(type != thisentry->type) X { X continue; X } X if(bestmatches < 1) X { X bestmatches = 1; X bestmatch = thisentry; X } X if(remov != thisentry->removable) X { X continue; X } X if(bestmatches < 2) X { X bestmatches = 2; X bestmatch = thisentry; X } X if(thisentry->showme) X printf("\n%s-\n%s-",thisentry->manufacturer, manu); X if(strcmp(thisentry->manufacturer, manu)) X { X continue; X } X if(bestmatches < 3) X { X bestmatches = 3; X bestmatch = thisentry; X } X if(thisentry->showme) X printf("\n%s-\n%s-",thisentry->model, model); X if(strcmp(thisentry->model, model)) X { X continue; X } X if(bestmatches < 4) X { X bestmatches = 4; X bestmatch = thisentry; X } X if(thisentry->showme) X printf("\n%s-\n%s-",thisentry->version, rev); X if(strcmp(thisentry->version, rev)) X { X continue; X } X if(bestmatches < 5) X { X bestmatches = 5; X bestmatch = thisentry; X break; X } X } X return(bestmatch); X} X Xstatic int recurse = 0; X/***********************************************\ X* Do a scsi operation asking a device if it is * X* ready. Use the scsi_cmd routine in the switch * X* table. * X\***********************************************/ Xscsi_ready(unit,target,lu,scsi_switch, flags) Xstruct scsi_switch *scsi_switch; X{ X struct scsi_test_unit_ready scsi_cmd; X struct scsi_xfer scsi_xfer; X volatile int rval; X int key; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X bzero(&scsi_xfer, sizeof(scsi_xfer)); X scsi_cmd.op_code = TEST_UNIT_READY; X X scsi_xfer.flags=flags | INUSE; X scsi_xfer.adapter=unit; X scsi_xfer.targ=target; X scsi_xfer.lu=lu; X scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd; X scsi_xfer.retries=8; X scsi_xfer.timeout=10000; X scsi_xfer.cmdlen=sizeof(scsi_cmd); X scsi_xfer.data=0; X scsi_xfer.datalen=0; X scsi_xfer.resid=0; X scsi_xfer.when_done=0; X scsi_xfer.done_arg=0; Xretry: scsi_xfer.error=0; X /*******************************************************\ X * do not use interrupts * X \*******************************************************/ X rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer); X if (rval != COMPLETE) X { X if(scsi_debug) X { X printf("scsi error, rval = 0x%x\n",rval); X printf("code from driver: 0x%x\n",scsi_xfer.error); X } X switch(scsi_xfer.error) X { X case XS_SENSE: X /*******************************************************\ X * Any sense value is illegal except UNIT ATTENTION * X * In which case we need to check again to get the * X * correct response. * X *( especially exabytes) * X \*******************************************************/ X if(scsi_xfer.sense.error_class == 7 ) X { X key = scsi_xfer.sense.ext.extended.sense_key ; X switch(key) X { X case 2: /* not ready BUT PRESENT! */ X return(COMPLETE); X case 6: X spinwait(1000); X if(scsi_xfer.retries--) X { X scsi_xfer.flags &= ~ITSDONE; X goto retry; X } X return(COMPLETE); X default: X if(scsi_debug) X printf("%d:%d,key=%x.", X target,lu,key); X } X } X return(HAD_ERROR); X case XS_BUSY: X spinwait(1000); X if(scsi_xfer.retries--) X { X scsi_xfer.flags &= ~ITSDONE; X goto retry; X } X return(COMPLETE); /* it's busy so it's there */ X case XS_TIMEOUT: X default: X return(HAD_ERROR); X } X } X return(COMPLETE); X} X/***********************************************\ X* Do a scsi operation asking a device what it is* X* Use the scsi_cmd routine in the switch table. * X\***********************************************/ Xscsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags) Xstruct scsi_switch *scsi_switch; Xu_char *inqbuf; X{ X struct scsi_inquiry scsi_cmd; X struct scsi_xfer scsi_xfer; X volatile int rval; X X bzero(&scsi_cmd, sizeof(scsi_cmd)); X bzero(&scsi_xfer, sizeof(scsi_xfer)); X scsi_cmd.op_code = INQUIRY; X scsi_cmd.length = sizeof(struct scsi_inquiry_data); X X scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE; X scsi_xfer.adapter=unit; X scsi_xfer.targ=target; X scsi_xfer.lu=lu; X scsi_xfer.retries=8; X scsi_xfer.timeout=10000; X scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd; X scsi_xfer.cmdlen= sizeof(struct scsi_inquiry); X scsi_xfer.data=inqbuf; X scsi_xfer.datalen=sizeof(struct scsi_inquiry_data); X scsi_xfer.resid=sizeof(struct scsi_inquiry_data); X scsi_xfer.when_done=0; X scsi_xfer.done_arg=0; Xretry: scsi_xfer.error=0; X /*******************************************************\ X * do not use interrupts * X \*******************************************************/ X if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE) X { X if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error); X switch(scsi_xfer.error) X { X case XS_NOERROR: X break; X case XS_SENSE: X /*******************************************************\ X * Any sense value is illegal except UNIT ATTENTION * X * In which case we need to check again to get the * X * correct response. * X *( especially exabytes) * X \*******************************************************/ X if((scsi_xfer.sense.error_class == 7 ) X && (scsi_xfer.sense.ext.extended.sense_key == 6)) X { /* it's changed so it's there */ X spinwait(1000); X { X if(scsi_xfer.retries--) X { X scsi_xfer.flags &= ~ITSDONE; X goto retry; X } X } X return( COMPLETE); X } X return(HAD_ERROR); X case XS_BUSY: X spinwait(1000); X if(scsi_xfer.retries--) X { X scsi_xfer.flags &= ~ITSDONE; X goto retry; X } X return(COMPLETE); /* it's busy so it's there */ X case XS_TIMEOUT: X default: X return(HAD_ERROR); X } X } X return(COMPLETE); X} X X X X X/***********************************************\ X* Utility routines often used in SCSI stuff * X\***********************************************/ X X/***********************************************\ X* convert a physical address to 3 bytes, * X* MSB at the lowest address, * X* LSB at the highest. * X\***********************************************/ X Xlto3b(val, bytes) Xu_char *bytes; X{ X *bytes++ = (val&0xff0000)>>16; X *bytes++ = (val&0xff00)>>8; X *bytes = val&0xff; X} X X/***********************************************\ X* The reverse of lto3b * X\***********************************************/ X_3btol(bytes) Xu_char *bytes; X{ X int rc; X rc = (*bytes++ << 16); X rc += (*bytes++ << 8); X rc += *bytes; X return(rc); X} X END-of-scsi/scsiconf.c echo x - scsi/scsi_all.h sed 's/^X//' >scsi/scsi_all.h << 'END-of-scsi/scsi_all.h' X/* X * HISTORY X * $Log: scsi_all.h,v $ X * X */ X X/* X * SCSI general interface description X */ X X X/* X * Largely written by Julian Elischer (julian@tfs.com) X * for TRW Financial Systems. X * X * TRW Financial Systems, in accordance with their agreement with Carnegie X * Mellon University, makes this software available to CMU to distribute X * or use in any manner that they see fit as long as this message is kept with X * the software. For this reason TFS also grants any other persons or X * organisations permission to use or modify this software. X * X * TFS supplies this software to be publicly redistributed X * on the understanding that TFS is not responsible for the correct X * functioning of this software in any circumstances. X * X */ X X/* X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 X */ X X/* X * SCSI command format X */ X X Xstruct scsi_generic X{ X u_char opcode; X u_char bytes[11]; X}; X Xstruct scsi_test_unit_ready X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[3]; X u_char link:1; X u_char flag:4; X u_char :3; X}; X Xstruct scsi_send_diag X{ X u_char op_code; X u_char uol:1; X u_char dol:1; X u_char selftest:1; X u_char :1; X u_char pf:1; X u_char lun:3; X u_char unused[1]; X u_char paramlen[2]; X u_char link:1; X u_char flag:4; X u_char :3; X}; X Xstruct scsi_sense X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[2]; X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_inquiry X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[2]; X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_mode_sense X{ X u_char op_code; X u_char :3; X u_char dbd:1; X u_char rsvd:1; X u_char lun:3; X u_char page_code:6; X u_char page_ctrl:2; X u_char unused; X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_mode_sense_big X{ X u_char op_code; X u_char :3; X u_char dbd:1; X u_char rsvd:1; X u_char lun:3; X u_char page_code:6; X u_char page_ctrl:2; X u_char unused[4]; X u_char length[2]; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_mode_select X{ X u_char op_code; X u_char sp:1; X u_char :3; X u_char pf:1; X u_char lun:3; X u_char unused[2]; X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_mode_select_big X{ X u_char op_code; X u_char sp:1; X u_char :3; X u_char pf:1; X u_char lun:3; X u_char unused[5]; X u_char length[2]; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_reserve X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[2]; X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_release X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[2]; X u_char length; X u_char link:1; X u_char flag:1; X u_char :6; X}; X Xstruct scsi_prevent X{ X u_char op_code; X u_char :5; X u_char lun:3; X u_char unused[2]; X u_char prevent:1; X u_char :7; X u_char link:1; X u_char flag:1; X u_char :6; X}; X#define PR_PREVENT 1 X#define PR_ALLOW 0 X X/* X * Opcodes X */ X X#define TEST_UNIT_READY 0x00 X#define REQUEST_SENSE 0x03 X#define INQUIRY 0x12 X#define MODE_SELECT 0x15 X#define MODE_SENSE 0x1a X#define START_STOP 0x1b X#define RESERVE 0x16 X#define RELEASE 0x17 X#define PREVENT_ALLOW 0x1e X#define POSITION_TO_ELEMENT 0x2b X#define MODE_SENSE_BIG 0x54 X#define MODE_SELECT_BIG 0x55 X#define MOVE_MEDIUM 0xa5 X#define READ_ELEMENT_STATUS 0xb8 X X X/* X * sense data format X */ X#define T_DIRECT 0 X#define T_SEQUENTIAL 1 X#define T_PRINTER 2 X#define T_PROCESSOR 3 X#define T_WORM 4 X#define T_READONLY 5 X#define T_SCANNER 6 X#define T_OPTICAL 7 X#define T_CHANGER 8 X#define T_COMM 9 X X#define T_REMOV 1 X#define T_FIXED 0 X Xstruct scsi_inquiry_data X{ X u_char device_type:5; X u_char device_qualifier:3; X u_char dev_qual2:7; X u_char removable:1; X u_char ansii_version:3; X u_char :5; X u_char response_format; X u_char additional_length; X u_char unused[2]; X u_char :3; X u_char can_link:1; X u_char can_sync:1; X u_char :3; X char vendor[8]; X char product[16]; X char revision[4]; X u_char extra[8]; X}; X X Xstruct scsi_sense_data X{ X u_char error_code:4; X u_char error_class:3; X u_char valid:1; X union X { X struct X { X u_char blockhi:5; X u_char vendor:3; X u_char blockmed; X u_char blocklow; X } unextended; X struct X { X u_char segment; X u_char sense_key:4; X u_char :1; X u_char ili:1; X u_char eom:1; X u_char filemark:1; X u_char info[4]; X u_char extra_len; X /* allocate enough room to hold new stuff X u_char cmd_spec_info[4]; X u_char add_sense_code; X u_char add_sense_code_qual; X u_char fru; X u_char sense_key_spec_1:7; X u_char sksv:1; X u_char sense_key_spec_2; X u_char sense_key_spec_3; X ( by increasing 16 to 26 below) */ X u_char extra_bytes[26]; X } extended; X }ext; X}; Xstruct scsi_sense_data_new X{ X u_char error_code:7; X u_char valid:1; X union X { X struct X { X u_char blockhi:5; X u_char vendor:3; X u_char blockmed; X u_char blocklow; X } unextended; X struct X { X u_char segment; X u_char sense_key:4; X u_char :1; X u_char ili:1; X u_char eom:1; X u_char filemark:1; X u_char info[4]; X u_char extra_len; X u_char cmd_spec_info[4]; X u_char add_sense_code; X u_char add_sense_code_qual; X u_char fru; X u_char sense_key_spec_1:7; X u_char sksv:1; X u_char sense_key_spec_2; X u_char sense_key_spec_3; X u_char extra_bytes[16]; X } extended; X }ext; X}; X Xstruct blk_desc X{ X u_char density; X u_char nblocks[3]; X u_char reserved; X u_char blklen[3]; X}; X Xstruct scsi_mode_header X{ X u_char data_length; /* Sense data length */ X u_char medium_type; X u_char dev_spec; X u_char blk_desc_len; X}; X Xstruct scsi_mode_header_big X{ X u_char data_length[2]; /* Sense data length */ X u_char medium_type; X u_char dev_spec; X u_char unused[2]; X u_char blk_desc_len[2]; X}; X X X/* X * Status Byte X */ X#define SCSI_OK 0x00 X#define SCSI_CHECK 0x02 X#define SCSI_BUSY 0x08 X#define SCSI_INTERM 0x10 END-of-scsi/scsi_all.h exit