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