Revised drivers from Julian.
[unix-history] / sys / scsi / sd.c
CommitLineData
15637ed4
RG
1/*
2 * Written by Julian Elischer (julian@tfs.com)
3 * for TRW Financial Systems for use under the MACH(2.5) operating system.
4 *
5 * TRW Financial Systems, in accordance with their agreement with Carnegie
6 * Mellon University, makes this software available to CMU to distribute
7 * or use in any manner that they see fit as long as this message is kept with
8 * the software. For this reason TFS also grants any other persons or
9 * organisations permission to use or modify this software.
10 *
11 * TFS supplies this software to be publicly redistributed
12 * on the understanding that TFS is not responsible for the correct
13 * functioning of this software in any circumstances.
14 *
15637ed4 15 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
98639498
RG
16 *
17 * $Id$
15637ed4
RG
18 */
19
20#define SPLSD splbio
21#define ESUCCESS 0
22#include <sd.h>
23#include <sys/types.h>
24#include <sys/param.h>
25#include <sys/dkbad.h>
26#include <sys/systm.h>
27#include <sys/conf.h>
28#include <sys/file.h>
29#include <sys/stat.h>
30#include <sys/ioctl.h>
31#include <sys/buf.h>
32#include <sys/uio.h>
33#include <sys/malloc.h>
34#include <sys/errno.h>
35#include <sys/disklabel.h>
36#include <scsi/scsi_all.h>
37#include <scsi/scsi_disk.h>
38#include <scsi/scsiconf.h>
39
40long int sdstrats,sdqueues;
41
42
43#include <ddb.h>
44#if NDDB > 0
45int Debugger();
46#else NDDB > 0
47#define Debugger()
48#endif NDDB > 0
49
50
51#define PAGESIZ 4096
52#define SECSIZE 512
53#define PDLOCATION 29
54#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff)
55#define SDOUTSTANDING 2
56#define SDQSIZE 4
57#define SD_RETRIES 4
58
59#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part)))
60#define UNITSHIFT 3
61#define PARTITION(z) (minor(z) & 0x07)
62#define RAW_PART 3
63#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
64
65#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART )
66
67struct buf sd_buf_queue[NSD];
68int sd_done();
69int sdstrategy();
70
71int sd_debug = 0;
72
73struct scsi_xfer *sd_free_xfer[NSD];
74int sd_xfer_block_wait[NSD];
75
76struct sd_data
77{
78 int flags;
79#define SDVALID 0x02 /* PARAMS LOADED */
80#define SDINIT 0x04 /* device has been init'd */
81#define SDWAIT 0x08 /* device has someone waiting */
82#define SDHAVELABEL 0x10 /* have read the label */
83#define SDDOSPART 0x20 /* Have read the DOS partition table */
84#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/
85 struct scsi_switch *sc_sw; /* address of scsi low level switch */
86 int ctlr; /* so they know which one we want */
87 int targ; /* our scsi target ID */
88 int lu; /* out scsi lu */
89 long int ad_info; /* info about the adapter */
90 int cmdscount; /* cmds allowed outstanding by board*/
91 int wlabel; /* label is writable */
92 struct disk_parms
93 {
94 u_char heads; /* Number of heads */
95 u_short cyls; /* Number of cylinders */
96 u_char sectors;/*dubious*/ /* Number of sectors/track */
97 u_short secsiz; /* Number of bytes/sector */
98 u_long disksize; /* total number sectors */
99 }params;
100 struct disklabel disklabel;
101 struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */
102 int partflags[MAXPARTITIONS]; /* per partition flags */
103#define SDOPEN 0x01
104 int openparts; /* one bit for each open partition */
105 unsigned int sd_start_of_unix; /* unix vs dos partitions */
106}sd_data[NSD];
107
108
109static int next_sd_unit = 0;
110/***********************************************************************\
111* The routine called by the low level scsi routine when it discovers *
112* A device suitable for this driver *
113\***********************************************************************/
114
115int sdattach(ctlr,targ,lu,scsi_switch)
116struct scsi_switch *scsi_switch;
117{
118 int unit,i;
119 unsigned char *tbl;
120 struct sd_data *sd;
121 struct disk_parms *dp;
122 long int ad_info;
123 struct scsi_xfer *sd_scsi_xfer;
124
125 unit = next_sd_unit++;
126 sd = sd_data + unit;
127 dp = &(sd->params);
128 if(scsi_debug & PRINTROUTINES) printf("sdattach: ");
129 /*******************************************************\
130 * Check we have the resources for another drive *
131 \*******************************************************/
132 if( unit >= NSD)
133 {
869c4419 134 printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",(unit + 1),NSD);
15637ed4
RG
135 return(0);
136 }
137 /*******************************************************\
138 * Store information needed to contact our base driver *
139 \*******************************************************/
140 sd->sc_sw = scsi_switch;
141 sd->ctlr = ctlr;
142 sd->targ = targ;
143 sd->lu = lu;
144 if(sd->sc_sw->adapter_info)
145 {
146 sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr));
147 sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
148 if(sd->cmdscount > SDOUTSTANDING)
149 {
150 sd->cmdscount = SDOUTSTANDING;
151 }
152 }
153 else
154 {
155 sd->ad_info = 1;
156 sd->cmdscount = 1;
157 }
158
159 i = sd->cmdscount;
160 sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i
161 ,M_TEMP, M_NOWAIT);
162 while(i-- )
163 {
164 sd_scsi_xfer->next = sd_free_xfer[unit];
165 sd_free_xfer[unit] = sd_scsi_xfer;
166 sd_scsi_xfer++;
167 }
168 /*******************************************************\
169 * Use the subdriver to request information regarding *
170 * the drive. We cannot use interrupts yet, so the *
171 * request must specify this. *
172 \*******************************************************/
173 sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
98639498 174 printf("sd%d: %dMB (%d total sec), %d cyl, %d head, %d sec, bytes/sec %d\n",
15637ed4 175 unit,
98639498
RG
176 dp->disksize / ((1024L * 1024L) / dp->secsiz),
177 dp->disksize,
15637ed4
RG
178 dp->cyls,
179 dp->heads,
180 dp->sectors,
181 dp->secsiz);
182 /*******************************************************\
183 * Set up the bufs for this device *
184 \*******************************************************/
185 sd->flags |= SDINIT;
186 return;
187
188}
189
190
191
192/*******************************************************\
193* open the device. Make sure the partition info *
194* is a up-to-date as can be. *
195\*******************************************************/
196sdopen(dev)
197{
198 int errcode = 0;
199 int unit, part;
200 struct disk_parms disk_parms;
201 struct sd_data *sd ;
202
203 unit = UNIT(dev);
204 part = PARTITION(dev);
205 sd = sd_data + unit;
206 if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
207 printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
208 , dev, unit, NSD, part);
209 /*******************************************************\
210 * Check the unit is legal *
211 \*******************************************************/
212 if ( unit >= NSD )
213 {
214 return(ENXIO);
215 }
216 /*******************************************************\
217 * Make sure the disk has been initialised *
218 * At some point in the future, get the scsi driver *
219 * to look for a new device if we are not initted *
220 \*******************************************************/
221 if (! (sd->flags & SDINIT))
222 {
223 return(ENXIO);
224 }
225
226 /*******************************************************\
227 * If it's been invalidated, and not everybody has *
228 * closed it then forbid re-entry. *
229 \*******************************************************/
230 if ((! (sd->flags & SDVALID))
231 && ( sd->openparts))
232 return(ENXIO);
233 /*******************************************************\
234 * Check that it is still responding and ok. *
235 * "unit attention errors should occur here if the drive *
236 * has been restarted or the pack changed *
237 \*******************************************************/
238
239 if(scsi_debug & TRACEOPENS)
240 printf("device is ");
241 if (sd_test_unit_ready(unit,0))
242 {
243 if(scsi_debug & TRACEOPENS) printf("not reponding\n");
244 return(ENXIO);
245 }
246 if(scsi_debug & TRACEOPENS)
247 printf("ok\n");
248 /*******************************************************\
249 * In case it is a funny one, tell it to start *
250 * not needed for most hard drives (ignore failure) *
251 \*******************************************************/
252 sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT);
253 if(scsi_debug & TRACEOPENS)
254 printf("started ");
255 /*******************************************************\
256 * Load the physical device parameters *
257 \*******************************************************/
258 sd_get_parms(unit, 0); /* sets SDVALID */
259 if (sd->params.secsiz != SECSIZE)
260 {
261 printf("sd%d: Can't deal with %d bytes logical blocks\n"
262 ,unit, sd->params.secsiz);
263 Debugger();
264 return(ENXIO);
265 }
266 if(scsi_debug & TRACEOPENS)
267 printf("Params loaded ");
268 /*******************************************************\
269 * Load the partition info if not already loaded *
270 \*******************************************************/
271 sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
272 if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART))
273 {
274 sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
275 return(errcode);
276 }
277 if(scsi_debug & TRACEOPENS)
278 printf("Disklabel loaded ");
279 /*******************************************************\
280 * Check the partition is legal *
281 \*******************************************************/
282 if ( part >= MAXPARTITIONS ) {
283 sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
284 return(ENXIO);
285 }
286 if(scsi_debug & TRACEOPENS)
287 printf("ok");
288 /*******************************************************\
289 * Check that the partition exists *
290 \*******************************************************/
291 if (( sd->disklabel.d_partitions[part].p_size == 0 )
292 && (part != RAW_PART))
293 {
294 sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
295 return(ENXIO);
296 }
297 sd->partflags[part] |= SDOPEN;
298 sd->openparts |= (1 << part);
299 if(scsi_debug & TRACEOPENS)
300 printf("open %d %d\n",sdstrats,sdqueues);
301 return(0);
302}
303
304/*******************************************************\
305* Get ownership of a scsi_xfer *
306* If need be, sleep on it, until it comes free *
307\*******************************************************/
308struct scsi_xfer *sd_get_xs(unit,flags)
309int flags;
310int unit;
311{
312 struct scsi_xfer *xs;
313 int s;
314
315 if(flags & (SCSI_NOSLEEP | SCSI_NOMASK))
316 {
317 if (xs = sd_free_xfer[unit])
318 {
319 sd_free_xfer[unit] = xs->next;
320 xs->flags = 0;
321 }
322 }
323 else
324 {
325 s = SPLSD();
326 while (!(xs = sd_free_xfer[unit]))
327 {
328 sd_xfer_block_wait[unit]++; /* someone waiting! */
329 sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1);
330 sd_xfer_block_wait[unit]--;
331 }
332 sd_free_xfer[unit] = xs->next;
333 splx(s);
334 xs->flags = 0;
335 }
336 return(xs);
337}
338
339/*******************************************************\
340* Free a scsi_xfer, wake processes waiting for it *
341\*******************************************************/
342sd_free_xs(unit,xs,flags)
343struct scsi_xfer *xs;
344int unit;
345int flags;
346{
347 int s;
348
349 if(flags & SCSI_NOMASK)
350 {
351 if (sd_xfer_block_wait[unit])
352 {
353 printf("doing a wakeup from NOMASK mode\n");
354 wakeup((caddr_t)&sd_free_xfer[unit]);
355 }
356 xs->next = sd_free_xfer[unit];
357 sd_free_xfer[unit] = xs;
358 }
359 else
360 {
361 s = SPLSD();
362 if (sd_xfer_block_wait[unit])
363 wakeup((caddr_t)&sd_free_xfer[unit]);
364 xs->next = sd_free_xfer[unit];
365 sd_free_xfer[unit] = xs;
366 splx(s);
367 }
368}
369
370/*******************************************************\
371* trim the size of the transfer if needed, *
372* called by physio *
373* basically the smaller of our max and the scsi driver's*
374* minphys (note we have no max) *
375\*******************************************************/
376/* Trim buffer length if buffer-size is bigger than page size */
377void sdminphys(bp)
378struct buf *bp;
379{
380 (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp);
381}
382
383/*******************************************************\
384* Actually translate the requested transfer into *
385* one the physical driver can understand *
386* The transfer is described by a buf and will include *
387* only one physical transfer. *
388\*******************************************************/
389
390int sdstrategy(bp)
391struct buf *bp;
392{
393 struct buf *dp;
394 unsigned int opri;
395 struct sd_data *sd ;
396 int unit;
397
398 sdstrats++;
399 unit = UNIT((bp->b_dev));
400 sd = sd_data + unit;
401 if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy ");
402 if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n",
403 unit,bp->b_bcount,bp->b_blkno);
404 sdminphys(bp);
405 /*******************************************************\
406 * If the device has been made invalid, error out *
407 \*******************************************************/
408 if(!(sd->flags & SDVALID))
409 {
410 bp->b_error = EIO;
411 goto bad;
412 }
413 /*******************************************************\
414 * "soft" write protect check *
415 \*******************************************************/
416 if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) {
417 bp->b_error = EROFS;
418 goto bad;
419 }
420 /*******************************************************\
421 * If it's a null transfer, return immediatly *
422 \*******************************************************/
423 if (bp->b_bcount == 0)
424 {
425 goto done;
426 }
427
428 /*******************************************************\
429 * Decide which unit and partition we are talking about *
430 * only raw is ok if no label *
431 \*******************************************************/
432 if(PARTITION(bp->b_dev) != RAW_PART)
433 {
434 if (!(sd->flags & SDHAVELABEL))
435 {
436 bp->b_error = EIO;
437 goto bad;
438 }
439
440 /*
441 * do bounds checking, adjust transfer. if error, process.
442 * if end of partition, just return
443 */
444 if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0)
445 goto done;
446 /* otherwise, process transfer request */
447 }
448
449 opri = SPLSD();
450 dp = &sd_buf_queue[unit];
451
452 /*******************************************************\
453 * Place it in the queue of disk activities for this disk*
454 \*******************************************************/
455 disksort(dp, bp);
456
457 /*******************************************************\
458 * Tell the device to get going on the transfer if it's *
459 * not doing anything, otherwise just wait for completion*
460 \*******************************************************/
461 sdstart(unit);
462
463 splx(opri);
464 return;
465bad:
466 bp->b_flags |= B_ERROR;
467done:
468
469 /*******************************************************\
470 * Correctly set the buf to indicate a completed xfer *
471 \*******************************************************/
472 bp->b_resid = bp->b_bcount;
473 biodone(bp);
474 return;
475}
476
477/***************************************************************\
478* sdstart looks to see if there is a buf waiting for the device *
479* and that the device is not already busy. If both are true, *
480* It deques the buf and creates a scsi command to perform the *
481* transfer in the buf. The transfer request will call sd_done *
482* on completion, which will in turn call this routine again *
483* so that the next queued transfer is performed. *
484* The bufs are queued by the strategy routine (sdstrategy) *
485* *
486* This routine is also called after other non-queued requests *
487* have been made of the scsi driver, to ensure that the queue *
488* continues to be drained. *
489* *
490* must be called at the correct (highish) spl level *
491\***************************************************************/
492/* sdstart() is called at SPLSD from sdstrategy and sd_done*/
493sdstart(unit)
494int unit;
495{
496 int drivecount;
497 register struct buf *bp = 0;
498 register struct buf *dp;
499 struct scsi_xfer *xs;
500 struct scsi_rw_big cmd;
501 int blkno, nblk;
502 struct sd_data *sd = sd_data + unit;
503 struct partition *p ;
504
505 if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit);
506 /*******************************************************\
507 * See if there is a buf to do and we are not already *
508 * doing one *
509 \*******************************************************/
510 if(!sd_free_xfer[unit])
511 {
512 return; /* none for us, unit already underway */
513 }
514
515 if(sd_xfer_block_wait[unit]) /* there is one, but a special waits */
516 {
517 return; /* give the special that's waiting a chance to run */
518 }
519
520
521 dp = &sd_buf_queue[unit];
522 if ((bp = dp->b_actf) != NULL) /* yes, an assign */
523 {
524 dp->b_actf = bp->av_forw;
525 }
526 else
527 {
528 return;
529 }
530
531 xs=sd_get_xs(unit,0); /* ok we can grab it */
532 xs->flags = INUSE; /* Now ours */
533 /*******************************************************\
534 * If the device has become invalid, abort all the *
535 * reads and writes until all files have been closed and *
536 * re-openned *
537 \*******************************************************/
538 if(!(sd->flags & SDVALID))
539 {
540 xs->error = XS_DRIVER_STUFFUP;
541 sd_done(unit,xs); /* clean up (calls sdstart) */
542 return ;
543 }
544 /*******************************************************\
545 * We have a buf, now we should move the data into *
546 * a scsi_xfer definition and try start it *
547 \*******************************************************/
548 /*******************************************************\
549 * First, translate the block to absolute *
550 \*******************************************************/
551 p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
552 blkno = bp->b_blkno + p->p_offset;
553 nblk = (bp->b_bcount + 511) >> 9;
554
555 /*******************************************************\
556 * Fill out the scsi command *
557 \*******************************************************/
558 bzero(&cmd, sizeof(cmd));
559 cmd.op_code = (bp->b_flags & B_READ)
560 ? READ_BIG : WRITE_BIG;
561 cmd.addr_3 = (blkno & 0xff000000) >> 24;
562 cmd.addr_2 = (blkno & 0xff0000) >> 16;
563 cmd.addr_1 = (blkno & 0xff00) >> 8;
564 cmd.addr_0 = blkno & 0xff;
565 cmd.length2 = (nblk & 0xff00) >> 8;
566 cmd.length1 = (nblk & 0xff);
567 /*******************************************************\
568 * Fill out the scsi_xfer structure *
569 * Note: we cannot sleep as we may be an interrupt *
570 \*******************************************************/
571 xs->flags |= SCSI_NOSLEEP;
572 xs->adapter = sd->ctlr;
573 xs->targ = sd->targ;
574 xs->lu = sd->lu;
575 xs->retries = SD_RETRIES;
576 xs->timeout = 10000;/* 10000 millisecs for a disk !*/
577 xs->cmd = (struct scsi_generic *)&cmd;
578 xs->cmdlen = sizeof(cmd);
579 xs->resid = bp->b_bcount;
580 xs->when_done = sd_done;
581 xs->done_arg = unit;
582 xs->done_arg2 = (int)xs;
583 xs->error = XS_NOERROR;
584 xs->bp = bp;
585 xs->data = (u_char *)bp->b_un.b_addr;
586 xs->datalen = bp->b_bcount;
587 /*******************************************************\
588 * Pass all this info to the scsi driver. *
589 \*******************************************************/
590
591
592
593 if ( (*(sd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED)
594 {
595 printf("sd%d: oops not queued",unit);
596 xs->error = XS_DRIVER_STUFFUP;
597 sd_done(unit,xs); /* clean up (calls sdstart) */
598 }
599 sdqueues++;
600}
601
602/*******************************************************\
603* This routine is called by the scsi interrupt when *
604* the transfer is complete.
605\*******************************************************/
606int sd_done(unit,xs)
607int unit;
608struct scsi_xfer *xs;
609{
610 struct buf *bp;
611 int retval;
612 int retries = 0;
613
614 if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit);
615 if (! (xs->flags & INUSE))
616 panic("scsi_xfer not in use!");
617 if(bp = xs->bp)
618 {
619 switch(xs->error)
620 {
621 case XS_NOERROR:
622 bp->b_error = 0;
623 bp->b_resid = 0;
624 break;
625
626 case XS_SENSE:
627 retval = (sd_interpret_sense(unit,xs));
628 if(retval)
629 {
630 bp->b_flags |= B_ERROR;
631 bp->b_error = retval;
632 }
633 break;
634
635 case XS_TIMEOUT:
636 printf("sd%d timeout\n",unit);
637
638 case XS_BUSY: /* should retry */ /* how? */
639 /************************************************/
640 /* SHOULD put buf back at head of queue */
641 /* and decrement retry count in (*xs) */
642 /* HOWEVER, this should work as a kludge */
643 /************************************************/
644 if(xs->retries--)
645 {
646 xs->error = XS_NOERROR;
647 xs->flags &= ~ITSDONE;
648 if ( (*(sd_data[unit].sc_sw->scsi_cmd))(xs)
649 == SUCCESSFULLY_QUEUED)
650 { /* don't wake the job, ok? */
651 return;
652 }
653 xs->flags |= ITSDONE;
654 } /* fall through */
655
656 case XS_DRIVER_STUFFUP:
657 bp->b_flags |= B_ERROR;
658 bp->b_error = EIO;
659 break;
660 default:
661 printf("sd%d: unknown error category from scsi driver\n"
662 ,unit);
663 }
664 biodone(bp);
665 sd_free_xs(unit,xs,0);
666 sdstart(unit); /* If there's anything waiting.. do it */
667 }
668 else /* special has finished */
669 {
670 wakeup(xs);
671 }
672}
673/*******************************************************\
674* Perform special action on behalf of the user *
675* Knows about the internals of this device *
676\*******************************************************/
677sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
678{
679 /* struct sd_cmd_buf *args;*/
680 int error = 0;
681 unsigned int opri;
682 unsigned char unit, part;
683 register struct sd_data *sd;
684
685
686 /*******************************************************\
687 * Find the device that the user is talking about *
688 \*******************************************************/
689 unit = UNIT(dev);
690 part = PARTITION(dev);
691 sd = &sd_data[unit];
692 if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit);
693
694 /*******************************************************\
695 * If the device is not valid.. abandon ship *
696 \*******************************************************/
697 if (!(sd_data[unit].flags & SDVALID))
698 return(EIO);
699 switch(cmd)
700 {
701
702 case DIOCSBAD:
703 error = EINVAL;
704 break;
705
706 case DIOCGDINFO:
707 *(struct disklabel *)addr = sd->disklabel;
708 break;
709
710 case DIOCGPART:
711 ((struct partinfo *)addr)->disklab = &sd->disklabel;
712 ((struct partinfo *)addr)->part =
713 &sd->disklabel.d_partitions[PARTITION(dev)];
714 break;
715
716 case DIOCSDINFO:
717 if ((flag & FWRITE) == 0)
718 error = EBADF;
719 else
720 error = setdisklabel(&sd->disklabel,
721 (struct disklabel *)addr,
722 /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0,
723 sd->dosparts);
724 if (error == 0) {
725 sd->flags |= SDHAVELABEL;
726 }
727 break;
728
729 case DIOCWLABEL:
730 sd->flags &= ~SDWRITEPROT;
731 if ((flag & FWRITE) == 0)
732 error = EBADF;
733 else
734 sd->wlabel = *(int *)addr;
735 break;
736
737 case DIOCWDINFO:
738 sd->flags &= ~SDWRITEPROT;
739 if ((flag & FWRITE) == 0)
740 error = EBADF;
741 else
742 {
743 if ((error = setdisklabel(&sd->disklabel
744 , (struct disklabel *)addr
745 , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0
746 , sd->dosparts)) == 0)
747 {
748 int wlab;
749
750 sd->flags |= SDHAVELABEL; /* ok write will succeed */
751
752 /* simulate opening partition 0 so write succeeds */
753 sd->openparts |= (1 << 0); /* XXX */
754 wlab = sd->wlabel;
755 sd->wlabel = 1;
756 error = writedisklabel(dev, sdstrategy,
757 &sd->disklabel, sd->dosparts);
758 sd->wlabel = wlab;
759 }
760 }
761 break;
762
763
764 default:
765 error = ENOTTY;
766 break;
767 }
768 return (error);
769}
770
771
772/*******************************************************\
773* Load the label information on the named device *
774\*******************************************************/
775int sdgetdisklabel(unit)
776unsigned char unit;
777{
778 /*unsigned int n, m;*/
779 char *errstring;
780 struct dos_partition *dos_partition_p;
781 struct sd_data *sd = sd_data + unit;
782
783 /*******************************************************\
784 * If the inflo is already loaded, use it *
785 \*******************************************************/
786 if(sd->flags & SDHAVELABEL) return(ESUCCESS);
787
788 bzero(&sd->disklabel,sizeof(struct disklabel));
789 /*******************************************************\
790 * make partition 3 the whole disk in case of failure *
791 * then get pdinfo *
792 \*******************************************************/
793 sd->disklabel.d_partitions[0].p_offset = 0;
794 sd->disklabel.d_partitions[0].p_size = sd->params.disksize;
795 sd->disklabel.d_partitions[RAW_PART].p_offset = 0;
796 sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize;
797 sd->disklabel.d_npartitions = MAXPARTITIONS;
798 sd->disklabel.d_secsize = 512; /* as long as it's not 0 */
799 sd->disklabel.d_ntracks = sd->params.heads;
800 sd->disklabel.d_nsectors = sd->params.sectors;
801 sd->disklabel.d_ncylinders = sd->params.cyls;
802 sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors;
803 if (sd->disklabel.d_secpercyl == 0)
804 {
805 sd->disklabel.d_secpercyl = 100;
806 /* as long as it's not 0 */
807 /* readdisklabel divides by it */
808 }
809
810 /*******************************************************\
98639498 811 * all the generic disklabel extraction routine *
15637ed4
RG
812 \*******************************************************/
813 if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3)
814 , sdstrategy
815 , &sd->disklabel
816 , sd->dosparts
817 , 0
818 , 0))
819 {
820 printf("sd%d: %s\n",unit, errstring);
821 return(ENXIO);
822 }
823 /*******************************************************\
824 * leave partition 2 "open" for raw I/O *
825 \*******************************************************/
826
827 sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
828 return(ESUCCESS);
829}
830
831/*******************************************************\
832* Find out from the device what it's capacity is *
833\*******************************************************/
834sd_size(unit, flags)
835{
836 struct scsi_read_cap_data rdcap;
837 struct scsi_read_capacity scsi_cmd;
838 int size;
839
840 /*******************************************************\
841 * make up a scsi command and ask the scsi driver to do *
842 * it for you. *
843 \*******************************************************/
844 bzero(&scsi_cmd, sizeof(scsi_cmd));
845 scsi_cmd.op_code = READ_CAPACITY;
846
847 /*******************************************************\
848 * If the command works, interpret the result as a 4 byte*
849 * number of blocks *
850 \*******************************************************/
851 if (sd_scsi_cmd(unit,
852 &scsi_cmd,
853 sizeof(scsi_cmd),
854 &rdcap,
855 sizeof(rdcap),
856 2000,
857 flags) != 0)
858 {
98639498 859 printf("sd0%: could not get size\n", unit);
15637ed4
RG
860 return(0);
861 } else {
862 size = rdcap.addr_0 + 1 ;
863 size += rdcap.addr_1 << 8;
864 size += rdcap.addr_2 << 16;
865 size += rdcap.addr_3 << 24;
866 }
867 return(size);
868}
869
870/*******************************************************\
871* Get scsi driver to send a "are you ready?" command *
872\*******************************************************/
873sd_test_unit_ready(unit,flags)
874int unit,flags;
875{
876 struct scsi_test_unit_ready scsi_cmd;
877
878 bzero(&scsi_cmd, sizeof(scsi_cmd));
879 scsi_cmd.op_code = TEST_UNIT_READY;
880
881 return (sd_scsi_cmd(unit,
882 &scsi_cmd,
883 sizeof(scsi_cmd),
884 0,
885 0,
886 100000,
887 flags));
888}
889
890/*******************************************************\
891* Prevent or allow the user to remove the tape *
892\*******************************************************/
893sd_prevent(unit,type,flags)
894int unit,type,flags;
895{
896 struct scsi_prevent scsi_cmd;
897
898 bzero(&scsi_cmd, sizeof(scsi_cmd));
899 scsi_cmd.op_code = PREVENT_ALLOW;
869c4419 900 scsi_cmd.how=type;
15637ed4
RG
901 return (sd_scsi_cmd(unit,
902 &scsi_cmd,
903 sizeof(scsi_cmd),
904 0,
905 0,
906 5000,
907 flags) );
908}
909/*******************************************************\
910* Get scsi driver to send a "start up" command *
911\*******************************************************/
912sd_start_unit(unit,flags)
913int unit,flags;
914{
915 struct scsi_start_stop scsi_cmd;
916
917 bzero(&scsi_cmd, sizeof(scsi_cmd));
918 scsi_cmd.op_code = START_STOP;
869c4419 919 scsi_cmd.how = SSS_START;
15637ed4
RG
920
921 return (sd_scsi_cmd(unit,
922 &scsi_cmd,
923 sizeof(scsi_cmd),
924 0,
925 0,
926 2000,
927 flags));
928}
929
930/*******************************************************\
931* Tell the device to map out a defective block *
932\*******************************************************/
933sd_reassign_blocks(unit,block)
934{
935 struct scsi_reassign_blocks scsi_cmd;
936 struct scsi_reassign_blocks_data rbdata;
937
938
939 bzero(&scsi_cmd, sizeof(scsi_cmd));
940 bzero(&rbdata, sizeof(rbdata));
941 scsi_cmd.op_code = REASSIGN_BLOCKS;
942
943 rbdata.length_msb = 0;
944 rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
945 rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff);
946 rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff);
947 rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
948 rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff);
949
950 return(sd_scsi_cmd(unit,
951 &scsi_cmd,
952 sizeof(scsi_cmd),
953 &rbdata,
954 sizeof(rbdata),
955 5000,
956 0));
957}
958
959#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
960
961/*******************************************************\
962* Get the scsi driver to send a full inquiry to the *
963* device and use the results to fill out the disk *
964* parameter structure. *
965\*******************************************************/
966
967int sd_get_parms(unit, flags)
968{
969 struct sd_data *sd = sd_data + unit;
970 struct disk_parms *disk_parms = &sd->params;
971 struct scsi_mode_sense scsi_cmd;
972 struct scsi_mode_sense_data
973 {
974 struct scsi_mode_header header;
975 struct blk_desc blk_desc;
976 union disk_pages pages;
977 }scsi_sense;
978 int sectors;
979
980 /*******************************************************\
981 * First check if we have it all loaded *
982 \*******************************************************/
983 if(sd->flags & SDVALID) return(0);
984 /*******************************************************\
985 * First do a mode sense page 3 *
986 \*******************************************************/
987 if (sd_debug)
988 {
989 bzero(&scsi_cmd, sizeof(scsi_cmd));
990 scsi_cmd.op_code = MODE_SENSE;
869c4419 991 scsi_cmd.page = 3;
15637ed4
RG
992 scsi_cmd.length = 0x24;
993 /*******************************************************\
994 * do the command, but we don't need the results *
995 * just print them for our interest's sake *
996 \*******************************************************/
997 if (sd_scsi_cmd(unit,
998 &scsi_cmd,
999 sizeof(scsi_cmd),
1000 &scsi_sense,
1001 sizeof(scsi_sense),
1002 2000,
1003 flags) != 0)
1004 {
98639498 1005 printf("sd%d: could not mode sense (3)\n", unit);
15637ed4
RG
1006 return(ENXIO);
1007 }
1008 printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n",
1009 unit,
1010 b2tol(scsi_sense.pages.disk_format.trk_z),
1011 b2tol(scsi_sense.pages.disk_format.alt_sec),
1012 b2tol(scsi_sense.pages.disk_format.alt_trk_z),
1013 b2tol(scsi_sense.pages.disk_format.alt_trk_v));
1014 printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n",
1015 b2tol(scsi_sense.pages.disk_format.ph_sec_t),
1016 b2tol(scsi_sense.pages.disk_format.bytes_s),
1017 b2tol(scsi_sense.pages.disk_format.interleave),
1018 sd_size(unit, flags),
1019 _3btol(scsi_sense.blk_desc.blklen));
1020 }
1021
1022
1023 /*******************************************************\
1024 * do a "mode sense page 4" *
1025 \*******************************************************/
1026 bzero(&scsi_cmd, sizeof(scsi_cmd));
1027 scsi_cmd.op_code = MODE_SENSE;
869c4419 1028 scsi_cmd.page = 4;
15637ed4
RG
1029 scsi_cmd.length = 0x20;
1030 /*******************************************************\
1031 * If the command worked, use the results to fill out *
1032 * the parameter structure *
1033 \*******************************************************/
1034 if (sd_scsi_cmd(unit,
1035 &scsi_cmd,
1036 sizeof(scsi_cmd),
1037 &scsi_sense,
1038 sizeof(scsi_sense),
1039 2000,
1040 flags) != 0)
1041 {
98639498 1042 printf("sd%d: could not mode sense (4)", unit);
15637ed4 1043 printf(" using ficticious geometry\n");
98639498
RG
1044 /*
1045 * use adaptec standard ficticious geometry
1046 * this depends on controllers and mode (ie, 1542C in
1047 * extended bios translation is different
1048 */
15637ed4
RG
1049 sectors = sd_size(unit, flags);
1050 disk_parms->heads = 64;
1051 disk_parms->sectors = 32;
1052 disk_parms->cyls = sectors/(64 * 32);
1053 disk_parms->secsiz = SECSIZE;
98639498 1054 disk_parms->disksize = sectors;
15637ed4
RG
1055 }
1056 else
1057 {
15637ed4
RG
1058 if (sd_debug)
1059 {
1060 printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
1061 _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2),
1062 scsi_sense.pages.rigid_geometry.nheads,
1063 b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp),
1064 b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc),
1065 b2tol(scsi_sense.pages.rigid_geometry.land_zone));
1066 }
1067
1068 /*******************************************************\
1069 * KLUDGE!!(for zone recorded disks) *
1070 * give a number of sectors so that sec * trks * cyls *
1071 * is <= disk_size *
1072 \*******************************************************/
1073 disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads;
1074 disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2);
1075 disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen);
1076
1077 sectors = sd_size(unit, flags);
98639498
RG
1078 disk_parms->disksize = sectors;
1079 sectors /= (disk_parms->cyls * disk_parms->heads);
15637ed4
RG
1080 disk_parms->sectors = sectors; /* dubious on SCSI*/
1081 }
1082
1083 sd->flags |= SDVALID;
1084 return(0);
1085}
1086
1087/*******************************************************\
1088* close the device.. only called if we are the LAST *
1089* occurence of an open device *
1090\*******************************************************/
1091sdclose(dev)
1092dev_t dev;
1093{
1094 unsigned char unit, part;
1095 unsigned int old_priority;
1096
1097 unit = UNIT(dev);
1098 part = PARTITION(dev);
1099 sd_data[unit].partflags[part] &= ~SDOPEN;
1100 sd_data[unit].openparts &= ~(1 << part);
1101 if(sd_data[unit].openparts == 0) /* if all partitions closed */
1102 {
1103 sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK);
1104 }
1105 return(0);
1106}
1107
1108/*******************************************************\
1109* ask the scsi driver to perform a command for us. *
1110* Call it through the switch table, and tell it which *
1111* sub-unit we want, and what target and lu we wish to *
1112* talk to. Also tell it where to find the command *
1113* how long int is. *
1114* Also tell it where to read/write the data, and how *
1115* long the data is supposed to be *
1116\*******************************************************/
1117int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags)
1118
1119int unit,flags;
1120struct scsi_generic *scsi_cmd;
1121int cmdlen;
1122int timeout;
1123u_char *data_addr;
1124int datalen;
1125{
1126 struct scsi_xfer *xs;
1127 int retval;
1128 int s;
1129 struct sd_data *sd = sd_data + unit;
1130
1131 if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit);
1132 if(sd->sc_sw) /* If we have a scsi driver */
1133 {
1134 xs = sd_get_xs(unit,flags); /* should wait unless booting */
1135 if(!xs)
1136 {
1137 printf("sd_scsi_cmd%d: controller busy"
1138 " (this should never happen)\n",unit);
1139 return(EBUSY);
1140 }
1141 xs->flags |= INUSE;
1142 /*******************************************************\
1143 * Fill out the scsi_xfer structure *
1144 \*******************************************************/
1145 xs->flags |= flags;
1146 xs->adapter = sd->ctlr;
1147 xs->targ = sd->targ;
1148 xs->lu = sd->lu;
1149 xs->retries = SD_RETRIES;
1150 xs->timeout = timeout;
1151 xs->cmd = scsi_cmd;
1152 xs->cmdlen = cmdlen;
1153 xs->data = data_addr;
1154 xs->datalen = datalen;
1155 xs->resid = datalen;
1156 xs->when_done = (flags & SCSI_NOMASK)
1157 ?(int (*)())0
1158 :sd_done;
1159 xs->done_arg = unit;
1160 xs->done_arg2 = (int)xs;
1161retry: xs->error = XS_NOERROR;
1162 xs->bp = 0;
1163 retval = (*(sd->sc_sw->scsi_cmd))(xs);
1164 switch(retval)
1165 {
1166 case SUCCESSFULLY_QUEUED:
1167 s = splbio();
1168 while(!(xs->flags & ITSDONE))
1169 sleep(xs,PRIBIO+1);
1170 splx(s);
1171
1172 case HAD_ERROR:
1173 /*printf("err = %d ",xs->error);*/
1174 switch(xs->error)
1175 {
1176 case XS_NOERROR:
1177 retval = ESUCCESS;
1178 break;
1179 case XS_SENSE:
1180 retval = (sd_interpret_sense(unit,xs));
1181 break;
1182 case XS_DRIVER_STUFFUP:
1183 retval = EIO;
1184 break;
1185 case XS_TIMEOUT:
1186 if(xs->retries-- )
1187 {
1188 xs->flags &= ~ITSDONE;
1189 goto retry;
1190 }
1191 retval = EIO;
1192 break;
1193 case XS_BUSY:
1194 if(xs->retries-- )
1195 {
1196 xs->flags &= ~ITSDONE;
1197 goto retry;
1198 }
1199 retval = EIO;
1200 break;
1201 default:
1202 retval = EIO;
1203 printf("sd%d: unknown error category from scsi driver\n"
1204 ,unit);
1205 }
1206 break;
1207 case COMPLETE:
1208 retval = ESUCCESS;
1209 break;
1210 case TRY_AGAIN_LATER:
1211 if(xs->retries-- )
1212 {
1213 xs->flags &= ~ITSDONE;
1214 goto retry;
1215 }
1216 retval = EIO;
1217 break;
1218 default:
1219 retval = EIO;
1220 }
1221 sd_free_xs(unit,xs,flags);
1222 sdstart(unit); /* check if anything is waiting fr the xs */
1223 }
1224 else
1225 {
1226 printf("sd%d: not set up\n",unit);
1227 return(EINVAL);
1228 }
1229 return(retval);
1230}
1231/***************************************************************\
1232* Look at the returned sense and act on the error and detirmine *
1233* The unix error number to pass back... (0 = report no error) *
1234\***************************************************************/
1235
1236int sd_interpret_sense(unit,xs)
1237int unit;
1238struct scsi_xfer *xs;
1239{
1240 struct scsi_sense_data *sense;
1241 int key;
1242 int silent;
1243
1244 /***************************************************************\
1245 * If the flags say errs are ok, then always return ok. *
1246 \***************************************************************/
1247 if (xs->flags & SCSI_ERR_OK) return(ESUCCESS);
1248 silent = (xs->flags & SCSI_SILENT);
1249
1250 sense = &(xs->sense);
869c4419 1251 switch(sense->error_code & SSD_ERRCODE)
15637ed4 1252 {
869c4419 1253 case 0x70:
15637ed4 1254 {
869c4419 1255 key=sense->ext.extended.flags & SSD_KEY;
15637ed4
RG
1256 switch(key)
1257 {
1258 case 0x0:
1259 return(ESUCCESS);
1260 case 0x1:
1261 if(!silent)
1262 {
1263 printf("sd%d: soft error(corrected) ", unit);
869c4419 1264 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1265 {
1266 printf("block no. %d (decimal)",
1267 (sense->ext.extended.info[0] <<24)|
1268 (sense->ext.extended.info[1] <<16)|
1269 (sense->ext.extended.info[2] <<8)|
1270 (sense->ext.extended.info[3] ));
1271 }
1272 printf("\n");
1273 }
1274 return(ESUCCESS);
1275 case 0x2:
1276 if(!silent)printf("sd%d: not ready\n ",
1277 unit);
1278 return(ENODEV);
1279 case 0x3:
1280 if(!silent)
1281 {
1282 printf("sd%d: medium error ", unit);
869c4419 1283 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1284 {
1285 printf("block no. %d (decimal)",
1286 (sense->ext.extended.info[0] <<24)|
1287 (sense->ext.extended.info[1] <<16)|
1288 (sense->ext.extended.info[2] <<8)|
1289 (sense->ext.extended.info[3] ));
1290 }
1291 printf("\n");
1292 }
1293 return(EIO);
1294 case 0x4:
1295 if(!silent)printf("sd%d: non-media hardware failure\n ",
1296 unit);
1297 return(EIO);
1298 case 0x5:
1299 if(!silent)printf("sd%d: illegal request\n ",
1300 unit);
1301 return(EINVAL);
1302 case 0x6:
1303 /***********************************************\
1304 * If we are not open, then this is not an error *
1305 * as we don't have state yet. Either way, make *
1306 * sure that we don't have any residual state *
1307 \***********************************************/
1308 if(!silent)printf("sd%d: Unit attention.\n ", unit);
1309 sd_data[unit].flags &= ~(SDVALID | SDHAVELABEL);
1310 if (sd_data[unit].openparts)
1311 {
1312 return(EIO);
1313 }
1314 return(ESUCCESS); /* not an error if nothing's open */
1315 case 0x7:
1316 if(!silent)
1317 {
1318 printf("sd%d: attempted protection violation ",
1319 unit);
869c4419 1320 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1321 {
1322 printf("block no. %d (decimal)\n",
1323 (sense->ext.extended.info[0] <<24)|
1324 (sense->ext.extended.info[1] <<16)|
1325 (sense->ext.extended.info[2] <<8)|
1326 (sense->ext.extended.info[3] ));
1327 }
1328 printf("\n");
1329 }
1330 return(EACCES);
1331 case 0x8:
1332 if(!silent)
1333 {
1334 printf("sd%d: block wrong state (worm)\n ",
1335 unit);
869c4419 1336 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1337 {
1338 printf("block no. %d (decimal)\n",
1339 (sense->ext.extended.info[0] <<24)|
1340 (sense->ext.extended.info[1] <<16)|
1341 (sense->ext.extended.info[2] <<8)|
1342 (sense->ext.extended.info[3] ));
1343 }
1344 printf("\n");
1345 }
1346 return(EIO);
1347 case 0x9:
1348 if(!silent)printf("sd%d: vendor unique\n",
1349 unit);
1350 return(EIO);
1351 case 0xa:
1352 if(!silent)printf("sd%d: copy aborted\n ",
1353 unit);
1354 return(EIO);
1355 case 0xb:
1356 if(!silent)printf("sd%d: command aborted\n ",
1357 unit);
1358 return(EIO);
1359 case 0xc:
1360 if(!silent)
1361 {
1362 printf("sd%d: search returned\n ",
1363 unit);
869c4419 1364 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1365 {
1366 printf("block no. %d (decimal)\n",
1367 (sense->ext.extended.info[0] <<24)|
1368 (sense->ext.extended.info[1] <<16)|
1369 (sense->ext.extended.info[2] <<8)|
1370 (sense->ext.extended.info[3] ));
1371 }
1372 printf("\n");
1373 }
1374 return(ESUCCESS);
1375 case 0xd:
1376 if(!silent)printf("sd%d: volume overflow\n ",
1377 unit);
1378 return(ENOSPC);
1379 case 0xe:
1380 if(!silent)
1381 {
1382 printf("sd%d: verify miscompare\n ",
1383 unit);
869c4419 1384 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1385 {
1386 printf("block no. %d (decimal)\n",
1387 (sense->ext.extended.info[0] <<24)|
1388 (sense->ext.extended.info[1] <<16)|
1389 (sense->ext.extended.info[2] <<8)|
1390 (sense->ext.extended.info[3] ));
1391 }
1392 printf("\n");
1393 }
1394 return(EIO);
1395 case 0xf:
1396 if(!silent)printf("sd%d: unknown error key\n ",
1397 unit);
1398 return(EIO);
1399 }
1400 break;
1401 }
869c4419 1402 default:
15637ed4 1403 {
869c4419 1404 if(!silent)printf("sd%d: code %d\n",
15637ed4 1405 unit,
869c4419
RG
1406 sense->error_code & SSD_ERRCODE);
1407 if(sense->error_code & SSD_ERRCODE_VALID)
15637ed4
RG
1408 if(!silent)printf("block no. %d (decimal)\n",
1409 (sense->ext.unextended.blockhi <<16)
1410 + (sense->ext.unextended.blockmed <<8)
1411 + (sense->ext.unextended.blocklow ));
1412 }
1413 return(EIO);
1414 }
1415}
1416
1417
1418
1419
1420int
1421sdsize(dev_t dev)
1422{
1423 int unit = UNIT(dev), part = PARTITION(dev), val;
1424 struct sd_data *sd;
1425
1426 if (unit >= NSD)
1427 return(-1);
1428
1429 sd = &sd_data[unit];
1430 if((sd->flags & SDINIT) == 0) return(-1);
1431 if (sd == 0 || (sd->flags & SDHAVELABEL) == 0)
1432 val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
1433 if ( val != 0 || sd->flags & SDWRITEPROT)
1434 return (-1);
1435
1436 return((int)sd->disklabel.d_partitions[part].p_size);
1437}
1438
98639498
RG
1439#ifdef SCSIDUMP
1440#include <vm/vm.h>
1441/***********************************************************************\
1442* dump all of physical memory into the partition specified, starting *
1443* at offset 'dumplo' into the partition. *
1444\***********************************************************************/
1445static struct scsi_xfer sx;
1446#define MAXTRANSFER 8 /* 1 page at a time */
1447int
1448sddump(dev_t dev) /* dump core after a system crash */
15637ed4 1449{
98639498
RG
1450 register struct sd_data *sd; /* disk unit to do the IO */
1451 long num; /* number of sectors to write */
1452 int unit, part, sdc;
1453 long blkoff, blknum, blkcnt;
1454 long nblocks;
1455 char *addr;
1456 struct scsi_rw_big cmd;
1457 extern int Maxmem;
1458 static sddoingadump = 0 ;
1459 extern caddr_t CADDR1; /* map the page we are about to write, here*/
1460 struct scsi_xfer *xs = &sx;
1461 int retval;
1462
1463 addr = (char *) 0; /* starting address */
1464
1465 /* toss any characters present prior to dump */
1466 while (sgetc(1))
1467 ;
1468
1469 /* size of memory to dump */
1470 num = Maxmem;
1471 unit = UNIT(dev); /* eventually support floppies? */
1472 part = PARTITION(dev); /* file system */
1473 /* check for acceptable drive number */
1474 if (unit >= NSD) return(ENXIO); /* 31 Jul 92*/
1475
1476 sd = sd_data+unit;
1477 /* was it ever initialized etc. ? */
1478 if (!(sd->flags & SDINIT)) return (ENXIO);
1479 if (sd->flags & SDVALID != SDVALID) return (ENXIO) ;
1480 if (sd->flags & SDWRITEPROT) return (ENXIO);
a0becc21 1481
98639498
RG
1482 /* Convert to disk sectors */
1483 num = (u_long) num * NBPG / sd->disklabel.d_secsize;
a0becc21 1484
98639498
RG
1485 /* check if controller active */
1486 if (sddoingadump) return(EFAULT);
a0becc21 1487
98639498
RG
1488 nblocks = sd->disklabel.d_partitions[part].p_size;
1489 blkoff = sd->disklabel.d_partitions[part].p_offset;
a0becc21 1490
98639498
RG
1491 /* check transfer bounds against partition size */
1492 if ((dumplo < 0) || ((dumplo + num) > nblocks))
1493 return(EINVAL);
1494
1495 sddoingadump = 1 ;
1496
1497 blknum = dumplo + blkoff;
1498 while (num > 0)
1499 {
1500 if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
1501 pmap_enter( kernel_pmap,
1502 CADDR1,
1503 trunc_page(addr),
1504 VM_PROT_READ,
1505 TRUE);
1506#ifndef NOT_TRUSTED
1507 /*******************************************************\
1508 * Fill out the scsi command *
1509 \*******************************************************/
1510 bzero(&cmd, sizeof(cmd));
1511 cmd.op_code = WRITE_BIG;
1512 cmd.addr_3 = (blknum & 0xff000000) >> 24;
1513 cmd.addr_2 = (blknum & 0xff0000) >> 16;
1514 cmd.addr_1 = (blknum & 0xff00) >> 8;
1515 cmd.addr_0 = blknum & 0xff;
1516 cmd.length2 = (blkcnt & 0xff00) >> 8;
1517 cmd.length1 = (blkcnt & 0xff);
1518 /*******************************************************\
1519 * Fill out the scsi_xfer structure *
1520 * Note: we cannot sleep as we may be an interrupt *
1521 \*******************************************************/
1522 bzero(xs, sizeof(sx));
1523 xs->flags |= SCSI_NOMASK|SCSI_NOSLEEP|INUSE;
1524 xs->adapter = sd->ctlr;
1525 xs->targ = sd->targ;
1526 xs->lu = sd->lu;
1527 xs->retries = SD_RETRIES;
1528 xs->timeout = 10000;/* 10000 millisecs for a disk !*/
1529 xs->cmd = (struct scsi_generic *)&cmd;
1530 xs->cmdlen = sizeof(cmd);
1531 xs->resid = blkcnt * 512;
1532 xs->when_done = 0;
1533 xs->done_arg = unit;
1534 xs->done_arg2 = (int)xs;
1535 xs->error = XS_NOERROR;
1536 xs->bp = 0;
1537 xs->data = (u_char *)CADDR1;
1538 xs->datalen = blkcnt * 512;
15637ed4 1539
98639498
RG
1540 /*******************************************************\
1541 * Pass all this info to the scsi driver. *
1542 \*******************************************************/
1543 retval = (*(sd->sc_sw->scsi_cmd))(xs);
1544 switch(retval)
1545 {
1546 case SUCCESSFULLY_QUEUED:
1547 case HAD_ERROR:
1548 return(ENXIO); /* we said not to sleep! */
1549 case COMPLETE:
1550 break;
1551 default:
1552 return(ENXIO); /* we said not to sleep! */
1553 }
1554#else NOT_TRUSTED
1555 printf ("sd%d: dump addr 0x%x, blk %d\n",unit,addr,blknum);
1556#endif
1557
1558 if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ;
1559 /* update block count */
1560 num -= MAXTRANSFER;
1561 blknum += MAXTRANSFER ;
1562 (int) addr += 512 * MAXTRANSFER;
1563
1564 /* operator aborting dump? */
1565 if (sgetc(1))
1566 return(EINTR);
1567 }
1568 return(0);
1569}
1570#else /* No SCSIDUMP CODE */
1571sddump()
1572{
1573 printf("\nsddump() -- not implemented\n");
1574 DELAY(20000000); /* 100 seconds */
1575 return(-1);
1576}
1577#endif