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