home *** CD-ROM | disk | FTP | other *** search
- From: tin@szebra.szebra.uucp (Tin Le)
- Newsgroups: alt.sources
- Subject: ST-0x 386/ix driver v1.0 pt3/6
- Message-ID: <1990Sep17.063006.25572@szebra.uucp>
- Date: 17 Sep 90 06:30:06 GMT
-
- 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 66AD 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)
-