tin@szebra.szebra.uucp (Tin Le) (09/17/90)
Seagate ST-0x 386/ix driver v1.0 #!/bin/sh # this is st02.03 (part 3 of a multipart archive) # do not concatenate these parts, unpack them in order with /bin/sh # file scsi.c continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 3; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping scsi.c' else echo 'x - continuing file scsi.c' sed 's/^X//' << 'SHAR_EOF' >> 'scsi.c' && X static void startbufferio(unit,bp) int unit; struct buf *bp; { X dorw(unit,BLPTOSEC(unit,PARTNO(minor(bp->b_dev)),bp->b_blkno), X bp->b_un.b_addr,bp->b_bcount,bp->b_flags,0,bp); } X /* This will start a pending io request in the system. If bp (the previous X request) is non-NULL, this will first remove bp from the list of X pending requests. This will then start a new request if there are any. X This can only be called with splnointrs, and when the unit is not busy. */ X static void startpendingreq(unit,bp) int unit; struct buf *bp; { X register struct buf *ap; X register int x; X X x=splnointrs(); X if (bp) X { X ap=bp->av_forw; X if (!ap) X if (d[unit].reqlist != bp) X ap=d[unit].reqlist; X } X else X ap=d[unit].reqlist; X /* ap is the next request to process, or NULL if there are none pending. */ X if (bp) X { X if (bp == d[unit].reqlist) X d[unit].reqlist=bp->av_forw; X if (bp->av_back) X bp->av_back->av_forw=bp->av_forw; X if (bp->av_forw) X bp->av_forw->av_back=bp->av_back; X bp->av_forw=NULL; X bp->av_back=NULL; X /* bp has now been removed from the list of requests. */ X } X X if (ap) /* start the next pending request if there are any */ X startbufferio(unit,ap); X X splx(x); } X /* This marks the unit not busy. This is used to mark the completion X of a command. This must absolutely be called exactly once for each and X every i/o request made. If the request was for an io buffer, this will X set b_flags&B_ERROR according to the completion; COK marks good completion. X If there are any processes sleeping for the drive to become not busy, X this will wake them up. If there is any pending block io, this will X start i/o for the next buffer. After a call to this, all data in the X d[unit] structure for the previous request will have been lost and the X next operation may be in progress. The scsi driver and controller should X be set to bus free phase before calling this. */ X static void marknotbusy(unit,completion) int unit,completion; { X register int x; X register struct buf *ap; X #ifdef DEBUG0 X printf("scsi: marknotbusy unit=%d completion=%d\n", X unit,completion); #endif X x=splnointrs(); X d[unit].busy=0; X d[unit].connected=0; /* just in case */ X d[unit].xfertime=0; /* we don't want any timeouts any more */ X ap=d[unit].currentbuf; X if (ap) X { X if (completion != COK) X ap->b_flags|=B_ERROR; X } X else X if (!d[unit].xferpolled) X wakeup(&d[unit].connected); X startpendingreq(unit,ap); /* This will start any pending io */ X if (ap) X iodone(ap); #ifdef DEBUG0 X printf("scsi: marknotbusy returning\n"); #endif X splx(x); } X /* This is the scsi interrupt service routine. This is called with a priority X lower than that of the timer tick, which is used to detect timeouts. X This is called (this ignores other calls) when a target is reselecting this X initiator. This will continue processing the reconnected request, and X if the request completes, this will (in lower-level routines) start the X next request automatically. */ X void scsiintr() { X register int a; X register int x; X register int unit; X long l; X X if (!(*cmdport & STSEL)) X { #ifdef DEBUG0 X printf("scsi: intr ignored (no SEL)\n"); #endif X return; /* The controller should only generate interrupts when select X rises. */ X } X for (l=0;l<20000l;l++) X if (*cmdport & STIO) X goto gotio; #ifdef DEBUG0 X printf("scsi: intr ignored (IO timeout)\n"); #endif X return; X gotio: X a=(*scsidataport) & 0xff; X if (!(a & MYADDR)) X { #ifdef DEBUG X printf("scsi: intr ignored (not my addr); addr=%x\n",a); #endif X return; X } X a&=(~MYADDR); X for (unit=0;unit < 8;unit++) X if (a & (unsigned char)(1<<unit)) X break; X if (unit >= 8 || (a & ~(unsigned char)(1<<unit))) X { #ifdef DEBUG X printf("scsi: intr ignored (invalid id); unit=%d a=%x\n",unit,a); #endif X return; X } X if (unit >= SCSIMAXDRIVES) X { #ifdef DEBUG X printf("scsi: intr ignored (unit %d >= SCSIMAXDRIVES %d)\n", X unit,SCSIMAXDRIVES); #endif X return; X } X x=splnointrs(); X if (d[unit].connected || !d[unit].busy) X { #ifdef DEBUG X printf("scsi: intr ignored (internal state): unit=%d connected=%d busy=%d\n", X unit,d[unit].connected,d[unit].busy); #endif X splx(x); X return; X } X if (d[unit].xferpolled) X { /* ooops... This is not the way it was supposed to happen... */ #ifdef DEBUG X printf("scsi: intr ignored (xfer is polled); unit=%d\n",unit); #endif X splx(x); X return; X } X *cmdport=CMDBASE|CMDBSY|CMDENABLE; /* acknowledge reselection */ X for (l=0;l<20000l;l++) X if (!(*cmdport & STSEL)) X goto selreleased; X /* timeout waiting for sel to be released */ X *cmdport=CMDBASE; #ifdef DEBUG X printf("scsi: intr ignored (timeout waiting for SEL to be released); unit=%d\n", X unit); #endif X splx(x); X return; X selreleased: X for (l=0;l<20000l;l++) X if (*cmdport & STBSY) X goto selectedandhavebsy; X /* timeout waiting for sel to be released */ X *cmdport=CMDBASE; #ifdef DEBUG X printf("scsi: intr ignored (timeout waiting for BSY after SEL to be released); unit=%d\n", X unit); #endif X splx(x); X return; X selectedandhavebsy: X *cmdport=CMDBASE|CMDENABLE; X d[unit].connected=1; X d[unit].xfertime=0; X intrserviced=1; X splx(x); /* allow timer ticks */ X if (d[unit].currentbuf) X { X a=doxfernosleep(unit); X doxferbufagain: X d[unit].connected=0; /* just in case */ X if (a != COK && a != CDISCONNECT) X { /* We got an error. We must retry the operation, and if the retry X count has elapsed, complete the operation with error. */ X if (d[unit].xferretries <= 0 || a == CBUSBUSY || a == CNOCONNECT) X { #ifdef DEBUG X printf("scsi: intr: cmd failed (%d); returning error\n",a); #endif X *cmdport=CMDBASE; X marknotbusy(unit,a); /* This may start a new operation */ X } X else X { X d[unit].xferretries--; #ifdef DEBUG X printf("scsi: intr: retrying command\n"); #endif X a=startscsi(unit); /* this will restart the command */ X goto doxferbufagain; X } X } X } X else X { /* it must be an interrupt-driven operation to an internal buffer */ X wakeup(&d[unit].connected); X /* leave the connected indicator on, and do no further processing X here. This will signal the sleeping operation that we are once X again connected. */ X } X intrserviced=0; X return; } X /* This is called using timeout() every 1/10th of a second. This is used X to solve timeout conditions related to lost interrupts and the like. X Note that this is usually entered with a priority higher than that of X the scsi driver. splnointrs should be defined so that this interrupt X is also masked out. There may also be a drawback in using splnointrs: X if the system clock is incremented with these timer interrupts, it might X lose some ticks when the scsi disk is being used. I hope Microport has X implemented the system clock in some more clever way. */ X void scsitick() { X register int a; X register int unit; X register int x; X X x=splnointrs(); X if (!intrserviced) /* if in the middle of a scsi interrupt, do nothing */ X { X for (unit=0;unit<SCSIMAXDRIVES;unit++) X { X if (!d[unit].busy || d[unit].connected || d[unit].xfertime == 0 || X d[unit].xfertimeout == 0 || d[unit].xferpolled) X continue; X d[unit].xfertime++; X if (d[unit].xfertime < d[unit].xfertimeout) X continue; X /* the timeout has elapsed. We can only assume that we have lost an X interrupt or there are problems on the target which prevent it from X reconnecting and completing the command. */ X d[unit].xfertime=0; /* will be reset in retry if appropriate */ X if (!d[unit].currentbuf) X { /* interrupt-driven transter to local buffer */ #ifdef DEBUG X printf("scsi: local intr driven xfer woken up by timer tick; unit=%d\n", X unit); #endif X wakeup(&d[unit].connected); /* !connected tells it to retry */ X continue; X } X a=CTIMEOUT; X retrytickforbuf: X if (a == COK || a == CDISCONNECT) X continue; X if (d[unit].xferretries == 0 || a == CBUSBUSY || a == CNOCONNECT) X { #ifdef DEBUG X printf("scsi: block xfer fails in timer tick; unit=%d, err=%d\n", X unit,a); #endif X marknotbusy(unit,a); /* This may start a new operation */ X continue; X } X d[unit].xferretries--; #ifdef DEBUG X printf("scsi: xfer retried in timer tick; unit=%d, err=%d\n", X unit,a); #endif X a=startscsi(unit); X goto retrytickforbuf; X } X } X timeout(scsitick,0,TICKSPERSECOND/10); X splx(x); } X /* This is the normal strcpy */ X static void strcpy(d,s) register unchar *d; register unchar *s; { X while (*s) X *d++=(*s++); X *d='\0'; } X /* This implements the request sense command. This returns a C* status. */ X static int requestsense(unit,buf,len,polled) int unit,len,polled; unchar *buf; { X unchar cmd[6]; X X if (len > 18) X len=18; X cmd[0]=SCSIREQSENSE; X cmd[1]=0; X cmd[2]=0; X cmd[3]=0; X cmd[4]=len; X cmd[5]=0; X X return doscsicmd(unit,cmd,buf,len,2,3,1,0,polled,NULL); } X /* This tests for drive readiness (with the scsi test unit ready command). X This returns a C* status. */ X static int testready(unit) int unit; { X unchar cmd[6]; X X cmd[0]=SCSITESTREADY; X cmd[1]=0; X cmd[2]=0; X cmd[3]=0; X cmd[4]=0; X cmd[5]=0; X X return doscsicmd(unit,cmd,NULL,0,1,1,1,0,1,NULL); } X /* This issues the inquiry command to the scsi drive to get its drive type X and other characteristics. This returns a C* status. */ X static int doinquiry(unit,buf,len,polled) int unit,len,polled; unchar *buf; { X unchar cmd[6]; X X if (len > 36) X len=36; X cmd[0]=SCSIINQUIRY; X cmd[1]=0; X cmd[2]=0; X cmd[3]=0; X cmd[4]=len; X cmd[5]=0; X return doscsicmd(unit,cmd,buf,len,150,3,1,0,polled,NULL); X /* the timeout is quite long to allow time for startup */ } X /* This reads the storage capacity and block size of the scsi drive */ X static int readcapacity(unit,buf,len,polled) int unit,len,polled; unchar *buf; { X unchar cmd[10]; X X if (len > 8) X len=8; X X cmd[0]=SCSIREADCAPACITY; X cmd[1]=0; X cmd[2]=0; X cmd[3]=0; X cmd[4]=0; X cmd[5]=0; X cmd[6]=0; X cmd[7]=0; X cmd[8]=0; X cmd[9]=0; X X if (doscsicmd(unit,cmd,buf,len,150,2,1,0,polled,NULL) != COK) X return 0; /* the timeout period is quite long to allow time for startup */ X return 1; } X /* This is used to initialize the drive at system startup time */ X static int initdrive(unit) int unit; { X int a,bs; X unchar buf[100]; X long s,l; X unsigned char *cp; X X d[unit].blocksize=0; X d[unit].busy=0; X d[unit].connected=0; X d[unit].nparts=0; X d[unit].nomsgs=0; X X a=testready(unit); X if (a != COK) X { X if (a != CERROR && a != CBUSY) X return 0; /* no point in waiting */ X printf("Waiting for unit %d powerup...\n",unit); X for (l=0;l<10000000l;l++) X if (l % 100000l == 0) X { X a=testready(unit); X if (a == COK) X break; X } X if (a != COK) X { X printf("Powerup timeout on drive %d\n",unit); X return 0; X } X } X a=requestsense(unit,buf,sizeof(buf),1); X if (a == CNOCONNECT || a == CBUSBUSY) X return 0; X if (a != COK) X { X printf("scsi drive %d is not responding properly.\n",unit); X return 0; X } #ifdef DEBUG0 X printf("scsi: initdrive: requestsense ok\n"); #endif X a=doinquiry(unit,buf,sizeof(buf),1); X if (a != COK) X { X printf("scsi drive %d: inquiry failed.\n",unit); X return 0; X } #ifdef DEBUG0 X printf("scsi: initdrive: doinquiry ok\n"); #endif X if (buf[0] != 0) X { X printf("scsi drive %d is on a direct access device\n",unit); X return 0; X } X buf[buf[4]+6]=0; X strcpy(d[unit].drivename,buf+8); X if (!readcapacity(unit,buf,sizeof(buf),1)) X { X d[unit].capacity=0; X bs=d[unit].blocksize=512; X printf("scsi drive %d: cannot read capacity\n",unit); X } X else X { X bs=d[unit].blocksize=((unsigned char)buf[6]<<8)+(unsigned char)buf[7]; X if (bs > BSIZE) X printf("scsi drive %d: blocksize=%d BSIZE=%d not supported\n", X unit,bs,BSIZE); X d[unit].capacity=(long)((unsigned char)buf[0]<<24)+ X (long)((unsigned char)buf[1]<<16)+ X (long)((unsigned char)buf[2]<<8)+ X (long)((unsigned char)buf[3]); X } X printf("scsi drive %d: %ldMB (%d byte sectors): %s\n", X unit,(d[unit].capacity*d[unit].blocksize+524288l)/1048576l, X d[unit].blocksize,d[unit].drivename); X a=dorw(unit,0l,buf,sizeof(buf),B_READ,1,NULL); X if (a != COK) X { X printf("scsi drive %d: could not read partition table\n",unit); X return 0; X } X for (cp=(unsigned char *)buf,a=0; X a<SCSIMAXPARTS-1 && X (cp[0] || cp[1] || cp[2] || cp[3] || cp[4] || cp[5]); X a++,cp+=6) X { X s=(long)(cp[0]<<16)+(cp[1]<<8)+cp[2]; X l=(long)(cp[3]<<16)+(cp[4]<<8)+cp[5]; X if (s == 0) X { X s++; X l--; X } X d[unit].parts[a].start=s; X d[unit].parts[a].len=l; X if (a == 0) X printf("partitions:"); X printf(" %ldMB",(l*bs+524288l)/1048576l); X } X if (a != 0) X printf("\n"); X d[unit].nparts=a; X d[unit].parts[SCSIMAXPARTS-1].start=0; X d[unit].parts[SCSIMAXPARTS-1].len=d[unit].capacity; X return 1; } X /*--------------------------------------------------------------------- -- scsiinit() -----------------------------------------------------------------------*/ void scsiinit() { X register int a; X extern char *sptalloc(); X X printf("\n%s\n",COPYRIGHT); X if (!baseaddr) X baseaddr=(unchar *)sptalloc(SCSISIZE/PAGESIZE,PG_P,(int)(SCSIBASE/PAGESIZE), X NOSLEEP); X if (!baseaddr) X { X printf("scsi driver error: could not sptalloc controller memory\n"); X return; X } X cmdport=baseaddr+SCSICONTROLOFS; X scsidataport=baseaddr+SCSIDATAOFS; X X timeouting=0; X for (a=0;a<SCSIMAXDRIVES;a++) X { X d[a].currentbuf=NULL; X d[a].reqlist=NULL; X } X for (a=0;a<SCSIMAXDRIVES;a++) X { X initdrive(a); X } X printf("\n"); } X void scsiopen(dev,flags) dev_t dev; int flags; { X int unit=UNITNO(minor(dev)), X part=PARTNO(minor(dev)), X x; X #ifdef DEBUG0 X printf("scsiopen: unit=%d part=%d\n",unit,part); #endif X if (!timeouting) X { X x=splnointrs(); /* in case scsitick makes any assumptions about spl */ X scsitick(); X splx(x); X timeouting=1; X } X if (unit >= SCSIMAXDRIVES || X (part != SCSIMAXPARTS-1 && X (d[unit].blocksize == 0 || part >= d[unit].nparts))) X u.u_error=ENXIO; } X void scsiclose() { #ifdef DEBUG0 X printf("scsiclose called\n"); #endif X /* do nothing */ } X void scsistrategy(bp) register struct buf *bp; { X int unit=UNITNO(minor(bp->b_dev)), X part=PARTNO(minor(bp->b_dev)), X nsecs,x; X register long sec; X register struct buf *ap; X register struct buf **app; X #ifdef DEBUG0 X printf("scsistrategy: unit=%d part=%d b_dev=%x b_bcount=%d b_blkno=%d b_flags=%x\n", X unit,part,bp->b_dev,bp->b_bcount,bp->b_blkno,bp->b_flags); #endif X if (unit >= SCSIMAXDRIVES || d[unit].blocksize == 0 || X bp->b_bcount % d[unit].blocksize != 0) X { X bp->b_flags|=B_ERROR; X bp->b_resid=bp->b_bcount; X iodone(bp); X return; X } X if (part == SCSIMAXPARTS-1) X sec=BLTOSEC(unit,bp->b_blkno); X else X { X sec=BLTOSEC(unit,bp->b_blkno); X if (part >= d[unit].nparts || sec > d[unit].parts[part].len) X { X bp->b_flags|=B_ERROR; X bp->b_resid=bp->b_bcount; X iodone(bp); X return; X } X if (sec == d[unit].parts[part].len) X { X bp->b_resid=bp->b_bcount; X iodone(bp); X return; X } X nsecs=(bp->b_bcount+d[unit].blocksize-1)/d[unit].blocksize; X if (sec+nsecs > d[unit].parts[part].len) X { X nsecs=d[unit].parts[part].len-sec; X bp->b_resid=bp->b_bcount-nsecs*d[unit].blocksize; X } X else X bp->b_resid=0; X sec+=d[unit].parts[part].start; X } X x=splnointrs(); X for (app=(&d[unit].reqlist),ap=NULL; X *app; X ap=(*app),app=(&(*app)->av_forw)) X { X if (sec < BLPTOSEC(unit,part,(*app)->b_blkno)) X { X bp->av_back=ap; X (*app)->av_back=bp; X bp->av_forw=(*app); X *app=bp; X goto haveinserted; X } X } X *app=bp; X bp->av_forw=NULL; X bp->av_back=ap; X haveinserted: X if (!d[unit].busy) X startbufferio(unit,bp); X splx(x); } X /* raw io read on the device */ X void scsiread(dev) int dev; { X physio(scsistrategy,&scsibuf,dev,B_READ); } X /* raw io write on the device */ X void scsiwrite(dev) int dev; { X physio(scsistrategy,&scsibuf,dev,B_WRITE); } X /* This formats the entire scsi drive. */ X static int formatscsidrive(unit,blocksize,interleave) int unit,blocksize,interleave; { X unchar cmd[10], buf[12]; X X if (blocksize <= 0) X blocksize=512; X printf("scsi: formatting unit %d with blocksize=%d, interleave=%d\n", X unit,blocksize,interleave); X X cmd[0]=SCSIMODESELECT; X cmd[1]=0; X cmd[2]=0; X cmd[3]=0; X cmd[4]=12; X cmd[5]=0; X X buf[0]=0; X buf[1]=0; X buf[2]=0; X buf[3]=8; X buf[4]=0; X buf[5]=0; X buf[6]=0; X buf[7]=0; X buf[8]=0; X buf[9]=(unchar)(blocksize>>16 & 0xff); X buf[10]=(unchar)(blocksize>>8 & 0xff); X buf[11]=(unchar)(blocksize & 0xff); X X if (doscsicmd(unit,cmd,buf,12,5,2,1,0,0,NULL) != COK) X printf("scsi: warning: mode select command returned error from drive %d\n", X unit); X cmd[0]=SCSIFORMATUNIT; X cmd[1]=0; /* primary and grown defect list only */ X cmd[2]=0; /* data pattern */ X cmd[3]=(unchar)(interleave>>8 & 0xff); X cmd[4]=(unchar)(interleave & 0xff); X cmd[5]=0; X X if (doscsicmd(unit,cmd,NULL,0,0,0,1,0,0,NULL) != COK) X { X printf("scsi: format failure.\n"); X return 0; X } X printf("scsi: format complete.\n"); X return 1; } X /* This checks that the current user is the super-user. Returns 0 if not. */ X static int chksuper() { X if (u.u_uid != 0) X { X u.u_error=EPERM; X return 0; X } X return 1; } X /* ioctl() for this device */ X int scsiioctl(dev,cmd,arg,mode) int dev, cmd, mode; unchar *arg; { X int unit=UNITNO(minor(dev)), X part=PARTNO(minor(dev)); X unchar *cp; X #ifdef DEBUG0 X printf("scsiioctl: unit=%d part=%d cmd=%d arg=%lx mode=%d\n", X unit,part,cmd,arg,mode); #endif /* DEBUG */ X X u.u_error=0; X if (unit >= SCSIMAXPARTS || X (part != SCSIMAXPARTS-1 && part >= d[unit].nparts)) X { X u.u_error=EINVAL; X return(1); X } X switch (cmd) X { X case SCSIIOREADCAP: X if (part == 15) X suword((int *)arg,(int)d[unit].capacity); X else X suword((int *)arg,(int)d[unit].parts[part].len); X break; X case SCSIIOREADTYPE: X for (cp=d[unit].drivename;*cp;cp++,arg++) X subyte(arg,*cp); X subyte(arg,0); X break; X case SCSIIOSETBLK: X if (!chksuper()) X break; X d[unit].blocksize=fuword((int *)arg); X break; X case SCSIIOFORMAT: X if (!chksuper()) X break; X if (!formatscsidrive(unit,d[unit].blocksize,fuword((int *)arg))) X u.u_error=EIO; X /* fall to next case */ X case SCSIIOINITUNIT: X initdrive(unit); X break; X case SCSIIOGETBLKSZ: X suword((int *)arg,d[unit].blocksize); X break; X default: X u.u_error=EINVAL; X break; X } X return(0); } X int scsiprint() { X printf("scsiprint called:\n"); X return(0); } SHAR_EOF echo 'File scsi.c is complete' && chmod 0644 scsi.c || echo 'restore of scsi.c failed' Wc_c="`wc -c < 'scsi.c'`" test 43689 -eq "$Wc_c" || echo 'scsi.c: original size 43689, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= scsi.h ============== if test -f 'scsi.h' -a X"$1" != X"-c"; then echo 'x - skipping scsi.h (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting scsi.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'scsi.h' && /* X 9/16/90 Tin Le X - Released to the world version 1.0 X X Modified for Interactive 386/ix v2.0.2 with some bug fixes X and minor enhancements. X SCSI disk driver for unix system V (Microport system V/386) This driver uses the ST-01 controller. This supports multiple initiators and multiple targets. X Copyright (c) 9.6.1988 Tatu Yl|nen Copyright (c) 16.9.1988 Tin Le X All rights reserved. X */ X #define SCSIMAXDRIVES 4 /* max # disk drives supported */ #define SCSIMAXPARTS 16 /* max partitions/drive */ X typedef struct scsidrivest { X unsigned char drivename[64]; /* drive type identification string */ X int blocksize; /* logical block size; if 0, not present */ X long capacity; /* total disk capacity in blocks */ X unsigned char nomsgs; /* set if drive does not support messages */ X int nparts; /* # partitions */ X struct partst X { X long start; /* starting sector number */ X long len; /* partition length */ X } parts[SCSIMAXPARTS]; X X unsigned char *xferbuf; /* transfer buffer address */ X int xferlen; /* data len to transfer */ X unsigned char *xfercmd; /* command to transfer */ X char xferslow; /* true if watch out for slow transfers */ X char xferstatus; /* status byte received from target */ X int xfertimeout; /* if nonzero, timeout in 1/10 sec */ X int xfertime; /* if nonzero, elapsed time waiting (1/10 sec) */ X int xferretries; /* if nonzero, retry the current request and decrement*/ X char xferphys; /* if true, transferring data with raw io */ X char xferpolled; /* if true, transfer must be polled */ X X unsigned char *savedbuf; /* saved buffer */ X int savedlen; /* saved lenght */ X unsigned char *savedcmd; /* saved command */ X X unsigned char *origbuf; /* original buffer */ X int origlen; /* original length */ X unsigned char *origcmd; /* original command */ X X struct buf *reqlist; /* queued requests */ X struct buf *currentbuf; /* buffer being executed */ X X char connected; /* true if connection to drive established */ X char busy; /* true if currently executing a command */ } SCSIDRIVE; X #define SCSIIOREADCAP 1 /* read capacity of partition or drive X (if part == 15); arg=&capacity */ #define SCSIIOREADTYPE 2 /* read drive type name (as a string); arg=buf */ #define SCSIIOFORMAT 3 /* reformat the drive; arg=&interleave */ #define SCSIIOSETBLK 4 /* set drive block size for format; arg=&size */ #define SCSIIOINITUNIT 5 /* re-initializes the unit, reading partition table */ #define SCSIIOGETBLKSZ 6 /* read sector size */ X /* Partitioning is done by writing on the first block of partition 15 X (the entire drive). Note that drive block size may not be the same as X system block size. Partition table format: each entry 3 bytes start, X 3 bytes length (in blocks, msb first), terminated by 6 zeroes. If first X partition starts at 0, it will be moved to 1 automatically; this appears X to be the convention under dos. */ X /* External defines for scsi routines 8/13/90 TL */ extern void scsiintr(); extern void scsitick(); extern scsiioctl(); extern void scsiinit(); extern void scsiopen(); extern void scsiclose(); extern void scsistrategy(); extern void scsiread(); extern void scsiwrite(); extern void sendtoscsi(); extern void getfromscsi(); X /* ctypes defines for scsiinit() 8/20/90 TL */ #define isspace(c) ((c) == ' ' ? 1 : ((c) == '\t' ? 1 : \ X ((c) == '\n' ? 1 : ((c) == '\r' ? 1 : 0)))) X #define isxdigit(c) ((c) >= '0' && (c) <= '9' ? 1 : \ X ((c) >= 'a' && (c) <= 'f' ? 1 : \ X ((c) >= 'A' && (c) <= 'F' ? 1 : 0))) SHAR_EOF chmod 0644 scsi.h || echo 'restore of scsi.h failed' Wc_c="`wc -c < 'scsi.h'`" test 3587 -eq "$Wc_c" || echo 'scsi.h: original size 3587, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= scsiasm.s ============== if test -f 'scsiasm.s' -a X"$1" != X"-c"; then echo 'x - skipping scsiasm.s (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting scsiasm.s (Text)' sed 's/^X//' << 'SHAR_EOF' > 'scsiasm.s' && X .file "scsiasm.s" / / fast transfer to/from the scsi controller / / Copyright (c) 1988 Tatu Yl|nen / All rights reserved. / X X .text X .align 4 X .globl getfromscsi X getfromscsi: X pushl %ebp X movl %esp,%ebp X pushl %esi X pushl %edi X push %es X movw %ds,%ax X movw %ax,%es X movl 8(%ebp),%edi X movl 12(%ebp),%ecx X movl scsidataport,%esi X cld X rep X smovb X pop %es X popl %edi X popl %esi X popl %ebp X ret X X .globl sendtoscsi sendtoscsi: X pushl %ebp X movl %esp,%ebp X pushl %esi X pushl %edi X push %es X movw %ds,%ax X movw %ax,%es X movl 8(%ebp),%esi X movl 12(%ebp),%ecx X movl scsidataport,%edi X cld X rep X smovb X pop %es X popl %edi X popl %esi X popl %ebp X ret SHAR_EOF chmod 0644 scsiasm.s || echo 'restore of scsiasm.s failed' Wc_c="`wc -c < 'scsiasm.s'`" test 805 -eq "$Wc_c" || echo 'scsiasm.s: original size 805, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= scsipart.c ============== if test -f 'scsipart.c' -a X"$1" != X"-c"; then echo 'x - skipping scsipart.c (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting scsipart.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'scsipart.c' && /* X SCSI disk partitioning program X Copyright (c) 9.6.1988 Tatu Yl|nen Copyright (c) 16.9.1990 Tin Le X All rights reserved. X */ X #include <stdio.h> #include <fcntl.h> #include "scsi.h" X #define DEV "/dev/rscsi%ds" /* must be raw device to use ioctls */ #define BDEV "/dev/scsi%ds" /* must be block device to use lseeks */ X char cdevname[80]; char bdevname[80]; unsigned char drivename[80]; unsigned char buf[4096]; int capacity; int interleave,blocksize; X int nparts; long partstart[SCSIMAXPARTS]; long partlen[SCSIMAXPARTS]; X int scsiunit; int scsihandle; int scsiblkhandle; X int asknumber(s,low,high) char *s; int low,high; { X int a; X X while (1) X { X printf("%s [%d-%d]: ",s, low, high); X if (scanf("%d",&a) == 1 && a >= low && a <= high) X return a; X printf("invalid input, try again.\n"); X fflush(stdin); X } } X readparts() { X unsigned char *cp; X X lseek(scsiblkhandle,0l,0); X if (read(scsiblkhandle,buf,1024) != 1024) X { X perror("Could not read partition table"); X exit(1); X } X for (nparts=0,cp=(unsigned char *)buf; X cp[0] || cp[1] || cp[2] || cp[3] || cp[4] || cp[5]; X nparts++,cp+=6) X { X if (nparts >= SCSIMAXPARTS-1) X { X printf("Invalid partition table - assuming no partitions\n"); X nparts=0; X return; X } X partstart[nparts]=(cp[0] << 16) + (cp[1] << 8) + cp[2]; X partlen[nparts]=(cp[3] << 16) + (cp[4] << 8) + cp[5]; X } } X saveparts() { X int a; X unsigned char *cp; X X for (a=0,cp=buf;a<nparts;a++,cp+=6) X { X cp[0]=partstart[a]>>16; X cp[1]=partstart[a]>>8; X cp[2]=partstart[a]; X cp[3]=partlen[a]>>16; X cp[4]=partlen[a]>>8; X cp[5]=partlen[a]; X } X memset(cp,0,6); X lseek(scsiblkhandle,0l,0); X if (write(scsiblkhandle,buf,1024) != 1024) X { X printf("error saving partition table\n"); X exit(1); X } } X int addpart(s,l) long s,l; { X if (nparts >= SCSIMAXPARTS-1) X { X printf("too many partitions\n"); X return 0; X } X partstart[nparts]=s; X partlen[nparts]=l; X nparts++; X return 1; } X int delpart(n) int n; { X int a; X X if (n < 0 || n >= nparts) X { X printf("invalid partition number\n"); X return 0; X } X for (a=n;a<nparts-1;a++) X { X partstart[a]=partstart[a+1]; X partlen[a]=partlen[a+1]; X } X nparts--; X return 1; } X printparts() { X int a; X X printf("capacity=%ld. Defined partitions:\n",capacity); X for (a=0;a<nparts;a++) X { X printf(" %d: start=%ld len=%ld blocks\n",a,partstart[a],partlen[a]); X } X if (nparts == 0) X printf(" no partitions defined.\n"); } X main() { X int a; X long s,l; X int errcount=10; X X printf("\nscsi disk drive formatting and partitioning utility V1.0\n"); X printf("Copyright (c) 9.6.1988 Tatu Yl|nen\n\n"); X printf("Warning: It is easy to destroy data with this program. Abort now\n"); X printf("if you are not sure what you are doing.\n"); X scsiunit=asknumber("Enter number of the scsi disk you wish to partition?", X 0,7); X sprintf(cdevname,DEV,scsiunit); X sprintf(bdevname,BDEV,scsiunit); X scsihandle=open(cdevname,O_RDWR); X if (scsihandle == -1) X { X perror(cdevname); X exit(1); X } X scsiblkhandle=open(bdevname,O_RDWR); X if (scsiblkhandle == -1) X { X perror(bdevname); X exit(1); X } X if (ioctl(scsihandle,SCSIIOREADTYPE,drivename) == -1) X perror("SCSIIOREADTYPE ioctl"); X if (ioctl(scsihandle,SCSIIOREADCAP,&capacity) == -1) X perror("SCSIIOREADCAP ioctl"); X if (ioctl(scsihandle,SCSIIOGETBLKSZ,&blocksize) == -1) X perror("SCSIIOGETBLKSZ ioctl"); X printf("Drive %d: %d blocks, blocksize=%d\n",scsiunit,capacity,blocksize); X printf("%s\n",drivename); X printf("Do you wish to format the unit (y/n)?\n"); X fflush(stdin); X gets(buf); X if (buf[0] == 'y' || buf[0] == 'Y') X { X printf("FORMATTING WILL DESTROY ALL AND ANY DATA ON THE DRIVE.\n"); X printf("ARE YOU SURE YOU WANT TO DO THIS (Y/N)?\n"); X gets(buf); X if (buf[0] != 'y' && buf[0] != 'Y') X exit(1); X blocksize=asknumber("Enter block size for the drive (usually 512)?", X 0,4096); X interleave=asknumber("Enter interleave factor for the drive (usually between 1 and 10)?", X 0,34); X while (ioctl(scsihandle,SCSIIOSETBLK,&blocksize) == -1 || X ioctl(scsihandle,SCSIIOFORMAT,&interleave) == -1 && errcount-->0) ; X if (errcount <= 0) X { X perror("Format failure"); X exit(1); X } X if (ioctl(scsihandle,SCSIIOREADCAP,&capacity) == -1) X perror("SCSIIOREADCAP ioctl"); X nparts=0; X saveparts(); X printf("Format complete. Drive capacity is %d blocks.\n",capacity); X } X if (ioctl(scsihandle,SCSIIOINITUNIT,NULL) == -1) X perror("SCSIIOINITUNIT ioctl"); X if (ioctl(scsihandle,SCSIIOREADTYPE,drivename) == -1) X perror("SCSIIOREADTYPE ioctl"); X if (ioctl(scsihandle,SCSIIOREADCAP,&capacity) == -1) X perror("SCSIIOREADCAP ioctl"); X if (ioctl(scsihandle,SCSIIOGETBLKSZ,&blocksize) == -1) X perror("SCSIIOGETBLKSZ ioctl"); X if (!readparts()) X nparts=0; X while (1) X { X printparts(); X a=asknumber("1 add partition 2 delete partition 8 quit (no save) 9 save", X 1,9); X switch (a) X { X case 1: /* add partition */ X s=asknumber("enter partition start in blocks?",0,capacity); X l=asknumber("enter partition length in blocks?",0,capacity-s); X addpart(s,l); X break; X case 2: /* delete partition */ X a=asknumber("enter partition number to delete?",0,nparts-1); X delpart(a); X break; X case 8: /* quit no save */ X printf("partition table not modified\n"); X exit(1); X case 9: /* quit, save modifications */ X printf("saving partition table\n"); X saveparts(); X if (ioctl(scsihandle,SCSIIOINITUNIT,NULL) == -1) X perror("SCSIIOINITUNIT ioctl"); X exit(0); X default: X printf("invalid command\n"); X break; X } X } } SHAR_EOF chmod 0644 scsipart.c || echo 'restore of scsipart.c failed' Wc_c="`wc -c < 'scsipart.c'`" test 6168 -eq "$Wc_c" || echo 'scsipart.c: original size 6168, current size' "$Wc_c" rm -f _shar_wnt_.tmp fi # ============= scsipart.uu ============== if test -f 'scsipart.uu' -a X"$1" != X"-c"; then echo 'x - skipping scsipart.uu (File already exists)' rm -f _shar_wnt_.tmp else > _shar_wnt_.tmp echo 'x - extracting scsipart.uu (Text)' sed 's/^X//' << 'SHAR_EOF' > 'scsipart.uu' && begin 755 scsipart M3 $$ $--]";(<P ;P( !P P$+ 0 '$@ &0= "$&P U - #L M"$ +G1E>'0 #0 T !Q( #0 ( "YD M871A [ A .P(0 !D'0 [$@ $ N8G-S M % F0 !0)D A!L " +F-O;6UE;G0 M '@- !09@ ( ,.0D)"#[ B+[(M%"(U4A1") M%>P(0 !2C54,4E#HW____VH Z. S "#Q 3H] , (/$#%#HQT< &H N $ M ": < ],.0D)#K7?]U$/]U#/]U"&@4"4 Z*\) "#Q!"-1?Q0:"$) M0 #H/@H (/$"#T! =16+10PY1?Q\#8M%$#E%_'\%BT7\ZQAH) E .AU M"0 66AX(4 Z)8] !9ZZ7)PU6+[%#KG9"0D.DR 0 D&H :@#_-=@W0 #H MOQT (/$#&@ ! :$ G0 #_-=@W0 #H6T8 (/$##T ! =!-H/PE .B? M" 66H!Z -' !9QP5,-T ,=%_$ G0 #IB )"X#P #D%3#= M 'P;:%X)0 #HY @ %G'!4PW0 Z:T "0H4PW0 "+5?P/MA+!XA"+ M3?P/MDD!P>$( ]&+3?P/MDD" ]&)%(50-T H4PW0 "+5?P/ME(#P>(0BTW\ M#[9)!,'A" /1BTW\#[9)!0/1B12%D#= /\%3#= (-%_ :+1?R . /A6W_ M__^+1?R > $ #X5@____BT7\@'@" ^%4____XM%_(!X P /A4;___^+1?R M> 0 #X4Y____BT7\@'@% ^%+/___\G#58OL4.G&_O__Z>( "0QT7\ M ,=%^$ G0 #K<HM%^(M5_(L4E5 W0 #!^A"($(M%^(M5_(L4E5 W0 #!^@B( M4 &+1?B+5?R*%)50-T B% "BT7XBU7\BQ25D#= ,'Z$(A0 XM%^(M5_(L4 ME9 W0 #!^@B(4 2+1?B+5?R*%)60-T B% %_T7\@T7X!J%,-T .47\?(1J M!FH _W7XZ%Y$ "#Q QJ &H _S78-T Z.0; "#Q QH 0 &A )T _S78 M-T Z"1% "#Q P] 0 '03:) )0 #H0 < %EJ >@H10 6<G#58OL@^P( MZ13___^0D.M,N \ Y!4PW0 !\$FBN"4 Z \' !9N #K*Z%,-T MBU4(B12%4#= *%,-T BU4,B12%D#= /\%3#= +@! ZP#)PU6+[.NO MD.MQ@WT( 'P*H4PW0 Y10A\$FC#"4 Z+@& !9N #K38M%"(E%_.LM MBT7\BU7\0HL4E5 W0 ")%(50-T BT7\BU7\0HL4E9 W0 ")%(60-T _T7\ MH4PW0 !(.47\?,C_#4PW0 "X 0 .L R<-5B^Q0ZXF0D)#K8_\U0#= &C= M"4 Z$8& "#Q C'1?P ZR>+1?S_-(60-T BT7\_S2%4#= /]U_&@! M"D Z!D& "#Q!#_1?RA3#= #E%_'S/@SU,-T '4+:"$*0 #H]@4 %G) MPU6+[%#KEY#IFP0 )#'1? * :#L*0 #HU04 %EH=PI .C*!0 66B< M"D Z+\% !9:-\*0 #HM 4 %EJ!VH : @+0 #HX?O__X/$#*/0-T _S70 M-T :#T+0 !H4"9 .@$$P @\0,_S70-T :$L+0 !HH"9 .CL$@ @\0, M:@)H4"9 .AY0@ @\0(H]0W0 "X_____SD%U#= '43:% F0 #HQ@0 %EJ M >@J0P 66H":* F0 #H14( (/$"*/8-T N/____\Y!=@W0 !U$VB@)D MZ)($ !9:@'H]D( %EH\"9 &H"_S74-T Z+,] "#Q P]_____W4+:%@+ M0 #H8P0 %EH0#= &H!_S74-T Z(P] "#Q P]_____W4+:&T+0 #H/ 0 M %EH2#= &H&_S74-T Z&4] "#Q P]_____W4+:($+0 #H%00 %G_-4@W M0 #_-4 W0 #_-= W0 !HE@M .AT! @\00:/ F0 !HN0M .AB! @\0( M:+T+0 #H500 %EH>"% .AV. 66A )T Z/\" !9#[8%0"= #UY M=!(/M@5 )T /5D /A1H! !HY M .@4! 66@<#$ Z D$ !9:$ G M0 #HO@( %D/M@5 )T /7D !T%@^V!4 G0 ]60 '0(:@'HRD$ %EH M ! &H :$4,0 #H!/K__X/$#*-(-T :B)J &AS#$ Z.[Y__^#Q RC1#= M .L :$@W0 !J!/\UU#= .A6/ @\0,/?____]TY&A$-T :@/_-=0W0 #H M.CP (/$##W_____=0J+1?#_3?"%P'^^@WWP '\3:+4,0 #HV@( %EJ >@^ M00 66A -T :@'_-=0W0 #H^SL (/$##W_____=0MHQ Q .BK @ 6<<% M3#= #H^_K___\U0#= &C8#$ Z <# "#Q AJ &H%_S74-T Z+4[ M "#Q P]_____W4+: @-0 #H90( %EH\"9 &H"_S74-T Z(X[ "#Q P] M_____W4+:!T-0 #H/@( %EH0#= &H!_S74-T Z&<[ "#Q P]_____W4+ M:#(-0 #H%P( %EH2#= &H&_S74-T Z$ [ "#Q P]_____W4+:$8-0 #H M\ $ %GH"OG__X7 =0K'!4PW0 Z/O[__]J"6H!:%L-0 #H@?C__X/$ M#(E%_(M%_.G( D/\U0#= &H :)8-0 #H8/C__X/$#(E%^*% -T *T7X M4&H :+<-0 #H1?C__X/$#(E%]/]U]/]U^.C0^O__@\0(Z9T "0H4PW0 !( M4&H :-D-0 #H&/C__X/$#(E%_/]U_.CZ^O__6>MX:/L-0 #HP0$ %EJ >BI M/P 66@9#D Z*X! !9Z(SY__]J &H%_S74-T Z%DZ "#Q P]_____W4+ M:#$.0 #H"0$ %EJ .AM/P 66A&#D Z'(! !9ZQPM 0 'SL/0@ !W MY3T ?-[_)(7P"$ Z?;^___)PU6+[(/L$.E;^___D%6+[(/L"%=64XMU M"(EU^(,]>"% !_,&AX(4 Z*X- !9/?____]U$CEU^ ^%A@ #/ 6UY? MR<.0D/\-?"% /\%>"% (L]>"% %=J"O\U?"% %;H0P$ (/$$(7 B]AT M!(O[*_Z+QP/P*05X(4 3U\(4 @SUX(4 'T%,\#K!I"A>"% ^^%84A M0 "+%)4\)4 *Q5\(4 .]!]"VAX(4 Z#TX !9A=L/A%?___].Q@8 BT7X M6UY?R<-5B^Q75K]8#D H:@00 Y!3 F0 !]#*$P)D BSR%; Y /]U".@) M/@ 68OPA?9T'U;_=0AJ N@//@ @\0,:@)H9@Y &H"Z/X] "#Q Q7Z-T] M !94%=J NCK/0 @\0,:@%H:0Y &H"Z-H] "#Q Q>7\G#D)"058OL4%>- M10R+T ^^!90A0 "I @ '45#[X%E"% *F ="B #90A0 ":(@A0 !2 M_W4(Z%D5 "#Q R+^ ^^!90A0 "I( '0*N/____]?R<.0D(O'7\G#D)"0 M5U:+?"0,BW0D$(I4)!2+3"0827PFK*HZPG0;27P=K*HZPG0227P4K*HZPG0) M27P+K*HZPG7<B\=>7\,SP%Y?PU6+[%"-10R+T%+_=0AH>"% .AA @\0, MR<-5B^Q0C440B]!2_W4,_W4(Z$< "#Q S)PY"058OL@^P45U:+?0B-11"+ M\,9%^ &+QXE%](E%\%?HOCP %F)1>S&1?D\5O]U#(U%[%#H"0 (/$#%Y? MR<.0D%6+[('L% $ %=64XM]"(MU#,>%_/[__P #'!:090 QP6H M&4 .F; @ D)"0_PVD&4 5_^U]/[__^@J$P @\0(/?____\/A) ! M #I?0( )"0D(/[*G43QX7P_O__ ^V!D:+V.L+D,>%\/[__P$ #' MA?C^__\ ZQR0D&N%^/[__PH#PRTP B87X_O__#[8&1HO8#[:#E1Q M *D$ ==B#O?C^__\ =0K'A?C^______]_B\.)A>S^__\]; '0)@[WL M_O__:'4&#[8&1HO8A=L/A,D! "#^UMU&HV% /___U!6Z"D( "#Q B%P(OP M#X2J 0 #[:#E1Q *D! =!/'A>S^__]L #[:#EAU (O8@_MN=%^# M/:@90 =5:#^V-T48/[6W1,_P6D&4 _P]]"5?H'PH %GK"8M'! ^V /]' M!(F%]/[__P^V@)4<0 "I" '70_PVD&4 5_^U]/[__^CI$0 @\0(/?__ M__]T4XO#/5L !T)#UC =!T]:0 ^$N #UN =$D]<P ^% MI@ (U%$%!7C84 ____4/^U^/[__U/_M?#^___H, 8 .F@ D)"0@[W\ M_O__ ^%Y0 +C_____6UY?R<.0@[WL_O__:'4?BT40!00 ")11"+0/QF MBQ6D&4 9HD0Z:H "0D(.][/[__VQU'XM%$ 4$ B440BT#\BQ6D&4 MB1#IA )"0D)"+11 %! (E%$(M _(L5I!E (D0ZVB-11!05_^U[/[_ M__^U^/[__U/_M?#^___H&P$ (/$&(F%[/[__X.][/[__P!T$8N%\/[__P&% M_/[__^LKD)"0@SVH&4 '03@[W\_O__ '4*N/____];7E_)PXN%_/[__UM> M7\G#D ^V!D:%P(O8=0Z+A?S^__];7E_)PY"0D ^V@Y4<0 "I" '1F@SVH M&4 '71_P6D&4 _P]]"U?H:0@ %GK"Y"0BT<$#[8 _T<$B87T_O__#[: ME1Q *D( =<[_#:090 !7_[7T_O__Z#$0 "#Q @]_____W6#QP6H&4 M 0 .ET____@_LE=0\/M@9&B]B#^R4/A?#\____!:090 #_#WT*5^CX!P M6>L*D(M'! ^V /]'!(F%]/[__SO##X6=_/__Z3#___]5B^R#[&A75E.+?1B- M1<"+\,=%M #'1; QT6L ,=%J #'1:0 QT6@ M (M%#"UD ?$<]% '= A<!\//\DA:P90 "0_T6HQT6X"@ .L3QT6X M" .L*D)"0QT6X$ /\%I!E /\/?1-7Z%$' !9ZQ.0D#/ 6UY?R<.0 MBT<$#[8 _T<$B]@]*P '09/2T !T#STP =#SIT@( )"0D/]%I/]- M$ ^.PP( /\%I!E /\/?0I7Z ' !9ZPJ0BT<$#[8 _T<$B]B#^S /A9L" M "#?0QI#X61 @ @WT0 0^.AP( /\%I!E /\/?0I7Z,0& !9ZPJ0BT<$ M#[8 _T<$B$6_#[[ /7@ !T#P^^1;\]6 ^%VP ^^1PT]/ '0% M@S\ ="/_!:090 #_#WT)5^A[!@ 6>L)BT<$#[8 _T<$B$6^ZRR0D&H!5@^^ M1PU0Z/<V "#Q P] 0 '4)B@:(1;[K!I"0QD6^__\%I!E ^^1;X/MH"5 M'$ J8 !T/,=%N! "#?1 "?Q__#:090 !7#[Y%OE#H"@X (/$"/]- M$.FV 0 D)"0#[Y%OHO8@VT0 NFD 0 D/\-I!E %</OD6^4.C;#0 @\0( SHAR_EOF true || echo 'restore of scsipart.uu failed' fi echo 'End of part 3' echo 'File scsipart.uu is continued in part 4' echo 4 > _shar_seq_.tmp exit 0 -- +----------------------------------------------------------------- Station Zebra ....!{claris,zorch}!szebra!tin Sunnyvale, CA (408) 739-1520 24hrs Telebit+ 300-19200bps Pub *NIX, Usenet and mail (no fee)