This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / scsi / sd.c
CommitLineData
15637ed4 1/*
d4284689 2 * Written by Julian Elischer (julian@dialix.oz.au)
15637ed4
RG
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 *
d4284689 15 * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
98639498 16 *
aa27e2cd 17 * $Id: sd.c,v 1.22 1994/04/05 03:23:32 davidg Exp $
15637ed4
RG
18 */
19
20#define SPLSD splbio
21#define ESUCCESS 0
22#include <sd.h>
23#include <sys/types.h>
24#include <sys/param.h>
16656850 25#include <sys/kernel.h>
15637ed4
RG
26#include <sys/dkbad.h>
27#include <sys/systm.h>
28#include <sys/conf.h>
29#include <sys/file.h>
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <sys/buf.h>
33#include <sys/uio.h>
34#include <sys/malloc.h>
35#include <sys/errno.h>
36#include <sys/disklabel.h>
37#include <scsi/scsi_all.h>
38#include <scsi/scsi_disk.h>
39#include <scsi/scsiconf.h>
16656850 40#include <vm/vm.h>
15637ed4 41
519fb2b7 42u_int32 sdstrats, sdqueues;
15637ed4 43
519fb2b7
RG
44#ifdef NetBSD
45#ifdef DDB
46int Debugger();
47#else /* DDB */
48#define Debugger()
49#endif /* DDB */
50#else /* NetBSD */
15637ed4
RG
51#include <ddb.h>
52#if NDDB > 0
519fb2b7 53#else /* NDDB > 0 */
fde1aeb2 54#define Debugger(s)
519fb2b7
RG
55#endif /* NDDB > 0 */
56#endif
15637ed4
RG
57
58#define PAGESIZ 4096
59#define SECSIZE 512
519fb2b7 60#define PDLOCATION 29
15637ed4
RG
61#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff)
62#define SDOUTSTANDING 2
63#define SDQSIZE 4
64#define SD_RETRIES 4
16656850 65#define MAXTRANSFER 8 /* 1 page at a time */
15637ed4
RG
66
67#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part)))
68#define UNITSHIFT 3
69#define PARTITION(z) (minor(z) & 0x07)
70#define RAW_PART 3
71#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
72
73#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART )
74
519fb2b7
RG
75errval sdgetdisklabel __P((unsigned char unit));
76errval sd_get_parms __P((int unit, int flags));
4c45483e
GW
77void sdstrategy __P((struct buf *));
78void sdstart __P((u_int32));
15637ed4 79
519fb2b7 80struct scsi_device sd_switch =
15637ed4 81{
519fb2b7
RG
82 NULL, /* Use default error handler */
83 sdstart, /* have a queue, served by this */
84 NULL, /* have no async handler */
85 NULL, /* Use default 'done' routine */
86 "sd",
87 0,
88 { 0, 0 }
89};
90
91struct sd_data {
92 u_int32 flags;
93#define SDINIT 0x04 /* device has been init'd */
94#define SDHAVELABEL 0x10 /* have read the label */
95#define SDDOSPART 0x20 /* Have read the DOS partition table */
96#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W) */
97 struct scsi_link *sc_link; /* contains our targ, lun etc. */
98 u_int32 ad_info; /* info about the adapter */
99 u_int32 cmdscount; /* cmds allowed outstanding by board */
100 boolean wlabel; /* label is writable */
101 struct disk_parms {
102 u_char heads; /* Number of heads */
103 u_int16 cyls; /* Number of cylinders */
104 u_char sectors; /*dubious *//* Number of sectors/track */
105 u_int16 secsiz; /* Number of bytes/sector */
106 u_int32 disksize; /* total number sectors */
107 } params;
108 struct disklabel disklabel;
109#ifdef NetBSD
110 struct cpu_disklabel cpudisklabel;
111#else
112 struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */
113#endif /* NetBSD */
114 u_int32 partflags[MAXPARTITIONS]; /* per partition flags */
15637ed4 115#define SDOPEN 0x01
519fb2b7
RG
116 u_int32 openparts; /* one bit for each open partition */
117 u_int32 sd_start_of_unix; /* unix vs dos partitions */
118 struct buf buf_queue;
119 u_int32 xfer_block_wait;
120} *sd_data[NSD];
15637ed4 121
519fb2b7 122static u_int32 next_sd_unit = 0;
15637ed4 123
16656850
RG
124static struct scsi_xfer sx;
125
519fb2b7
RG
126/*
127 * The routine called by the low level scsi routine when it discovers
128 * a device suitable for this driver.
129 */
130errval
131sdattach(sc_link)
132 struct scsi_link *sc_link;
15637ed4 133{
519fb2b7 134 u_int32 unit;
15637ed4
RG
135 struct sd_data *sd;
136 struct disk_parms *dp;
15637ed4
RG
137
138 unit = next_sd_unit++;
519fb2b7
RG
139 SC_DEBUG(sc_link, SDEV_DB2, ("sdattach: "));
140 /*
141 * Check we have the resources for another drive
142 */
143 if (unit >= NSD) {
144 printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",
145 (unit + 1), NSD);
146 return 0;
15637ed4 147 }
519fb2b7
RG
148 if (sd_data[unit]) {
149 printf("sd%d: unit already has storage allocated!\n", unit);
150 return 0;
d4284689 151 }
519fb2b7
RG
152 sd = sd_data[unit] = malloc(sizeof(struct sd_data), M_DEVBUF, M_NOWAIT);
153 if (!sd) {
d4284689 154 printf("malloc failed in sd.c\n");
519fb2b7 155 return (0);
d4284689 156 }
519fb2b7
RG
157 bzero(sd, sizeof(struct sd_data));
158
159 dp = &(sd->params);
160 /*
161 * Store information needed to contact our base driver
162 */
163 sd->sc_link = sc_link;
164 sc_link->device = &sd_switch;
165 sc_link->dev_unit = unit;
166
167 if (sd->sc_link->adapter->adapter_info) {
168 sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit));
169 sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
170 if (sd->cmdscount > SDOUTSTANDING) {
15637ed4
RG
171 sd->cmdscount = SDOUTSTANDING;
172 }
519fb2b7 173 } else {
15637ed4 174 sd->ad_info = 1;
519fb2b7
RG
175 sd->cmdscount = 1;
176 }
177 sc_link->opennings = sd->cmdscount;
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);
98639498 184 printf("sd%d: %dMB (%d total sec), %d cyl, %d head, %d sec, bytes/sec %d\n",
519fb2b7 185 unit,
4d486ab8 186 dp->disksize / ((1024L * 1024L) / dp->secsiz),
519fb2b7
RG
187 dp->disksize,
188 dp->cyls,
189 dp->heads,
190 dp->sectors,
191 dp->secsiz);
15637ed4 192 sd->flags |= SDINIT;
519fb2b7 193 return 0;
15637ed4
RG
194}
195
519fb2b7
RG
196/*
197 * open the device. Make sure the partition info is a up-to-date as can be.
198 */
199errval
15637ed4 200sdopen(dev)
519fb2b7 201 int dev; /* XXX should be dev_t, but avoid promotion problems for now */
15637ed4 202{
519fb2b7
RG
203 errval errcode = 0;
204 u_int32 unit, part;
205 struct sd_data *sd;
206 struct scsi_link *sc_link;
15637ed4
RG
207
208 unit = UNIT(dev);
209 part = PARTITION(dev);
d4284689 210 sd = sd_data[unit];
519fb2b7
RG
211 /*
212 * Check the unit is legal
213 */
214 if (unit >= NSD) {
215 return (ENXIO);
15637ed4 216 }
519fb2b7
RG
217 /*
218 * Make sure the disk has been initialised
219 * At some point in the future, get the scsi driver
220 * to look for a new device if we are not initted
221 */
222 if ((!sd) || (!(sd->flags & SDINIT))) {
223 return (ENXIO);
15637ed4 224 }
519fb2b7
RG
225 sc_link = sd->sc_link;
226
227 SC_DEBUG(sc_link, SDEV_DB1,
228 ("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
229 ,dev, unit, NSD, part));
230
231 /*
232 * "unit attention" errors should occur here if the
233 * drive has been restarted or the pack changed.
234 * just ingnore the result, it's a decoy instruction
235 * The error code will act on the error though
236 * and invalidate any media information we had.
237 */
238 scsi_test_unit_ready(sc_link, 0);
239
240 /*
241 * If it's been invalidated, then forget the label
242 */
243 sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */
244 if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
245 sd->flags &= ~SDHAVELABEL;
15637ed4 246
519fb2b7
RG
247 /*
248 * If somebody still has it open, then forbid re-entry.
249 */
250 if (sd->openparts) {
251 errcode = ENXIO;
252 goto bad;
253 }
254 }
255 /*
256 * In case it is a funny one, tell it to start
257 * not needed for most hard drives (ignore failure)
258 */
259 scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT);
260
261 /*
262 * Check that it is still responding and ok.
263 */
264 if (scsi_test_unit_ready(sc_link, 0)) {
265 SC_DEBUG(sc_link, SDEV_DB3, ("device not reponding\n"));
266 errcode = ENXIO;
267 goto bad;
d4284689 268 }
519fb2b7
RG
269 SC_DEBUG(sc_link, SDEV_DB3, ("device ok\n"));
270
271 /*
272 * Load the physical device parameters
273 */
274 sd_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */
275 if (sd->params.secsiz != SECSIZE) { /* XXX One day... */
276 printf("sd%d: Can't deal with %d bytes logical blocks\n",
277 unit, sd->params.secsiz);
fde1aeb2 278 Debugger("sd");
519fb2b7
RG
279 errcode = ENXIO;
280 goto bad;
15637ed4 281 }
519fb2b7
RG
282 SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
283
284 /* Lock the pack in. */
285 scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT);
286
287 /*
288 * Load the partition info if not already loaded.
289 */
290 if ((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) {
291 goto bad;
15637ed4 292 }
519fb2b7
RG
293 SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded "));
294 /*
295 * Check the partition is legal
296 */
297 if (part >= MAXPARTITIONS) {
298 errcode = ENXIO;
299 goto bad;
15637ed4 300 }
519fb2b7
RG
301 SC_DEBUG(sc_link, SDEV_DB3, ("partition ok"));
302
303 /*
304 * Check that the partition exists
305 */
306 if ((sd->disklabel.d_partitions[part].p_size == 0)
307 && (part != RAW_PART)) {
308 errcode = ENXIO;
309 goto bad;
15637ed4
RG
310 }
311 sd->partflags[part] |= SDOPEN;
312 sd->openparts |= (1 << part);
519fb2b7
RG
313 SC_DEBUG(sc_link, SDEV_DB3, ("open %d %d\n", sdstrats, sdqueues));
314 return 0;
15637ed4 315
519fb2b7
RG
316bad:
317 if (!(sd->openparts)) {
318 scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
319 sc_link->flags &= ~SDEV_OPEN;
15637ed4 320 }
519fb2b7 321 return errcode;
15637ed4
RG
322}
323
519fb2b7
RG
324/*
325 * close the device.. only called if we are the LAST occurence of an open
326 * device. Convenient now but usually a pain.
327 */
328errval
329sdclose(dev)
330 dev_t dev;
15637ed4 331{
519fb2b7
RG
332 unsigned char unit, part;
333 struct sd_data *sd;
334
335 unit = UNIT(dev);
336 part = PARTITION(dev);
337 sd = sd_data[unit];
338 sd->partflags[part] &= ~SDOPEN;
339 sd->openparts &= ~(1 << part);
340 scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
341 if (!(sd->openparts))
342 sd->sc_link->flags &= ~SDEV_OPEN;
343 return 0;
15637ed4
RG
344}
345
519fb2b7
RG
346/*
347 * trim the size of the transfer if needed, called by physio
348 * basically the smaller of our max and the scsi driver's
349 * minphys (note we have no max)
350 *
351 * Trim buffer length if buffer-size is bigger than page size
352 */
353void
354sdminphys(bp)
355 struct buf *bp;
15637ed4 356{
519fb2b7 357 (*(sd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
15637ed4
RG
358}
359
519fb2b7
RG
360/*
361 * Actually translate the requested transfer into one the physical driver
362 * can understand. The transfer is described by a buf and will include
363 * only one physical transfer.
364 */
4c45483e 365void
519fb2b7
RG
366sdstrategy(bp)
367 struct buf *bp;
15637ed4 368{
519fb2b7
RG
369 struct buf *dp;
370 u_int32 opri;
371 struct sd_data *sd;
372 u_int32 unit;
15637ed4
RG
373
374 sdstrats++;
375 unit = UNIT((bp->b_dev));
d4284689 376 sd = sd_data[unit];
519fb2b7
RG
377 SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy "));
378 SC_DEBUG(sd->sc_link, SDEV_DB1,
379 (" %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
15637ed4 380 sdminphys(bp);
519fb2b7
RG
381 /*
382 * If the device has been made invalid, error out
383 */
384 if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) {
385 sd->flags &= ~SDHAVELABEL;
15637ed4
RG
386 bp->b_error = EIO;
387 goto bad;
388 }
519fb2b7
RG
389 /*
390 * "soft" write protect check
391 */
15637ed4
RG
392 if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) {
393 bp->b_error = EROFS;
394 goto bad;
395 }
519fb2b7
RG
396 /*
397 * If it's a null transfer, return immediatly
398 */
399 if (bp->b_bcount == 0) {
15637ed4
RG
400 goto done;
401 }
519fb2b7
RG
402 /*
403 * Decide which unit and partition we are talking about
404 * only raw is ok if no label
405 */
406 if (PARTITION(bp->b_dev) != RAW_PART) {
407 if (!(sd->flags & SDHAVELABEL)) {
15637ed4
RG
408 bp->b_error = EIO;
409 goto bad;
410 }
15637ed4
RG
411 /*
412 * do bounds checking, adjust transfer. if error, process.
413 * if end of partition, just return
414 */
519fb2b7 415 if (bounds_check_with_label(bp, &sd->disklabel, sd->wlabel) <= 0)
15637ed4
RG
416 goto done;
417 /* otherwise, process transfer request */
aa27e2cd
DG
418 } else {
419 bp->b_pblkno = bp->b_blkno;
420 bp->b_resid = 0;
15637ed4 421 }
15637ed4 422 opri = SPLSD();
519fb2b7 423 dp = &sd->buf_queue;
15637ed4 424
8387479d
DG
425 /*
426 * Use a bounce buffer if necessary
427 */
428#ifndef NOBOUNCE
429 if (sd->sc_link->flags & SDEV_BOUNCE)
430 vm_bounce_alloc(bp);
431#endif
432
519fb2b7
RG
433 /*
434 * Place it in the queue of disk activities for this disk
435 */
2157b04d 436 cldisksort(dp, bp, 64*1024);
15637ed4 437
519fb2b7
RG
438 /*
439 * Tell the device to get going on the transfer if it's
440 * not doing anything, otherwise just wait for completion
441 */
15637ed4
RG
442 sdstart(unit);
443
444 splx(opri);
4c45483e 445 return /*0*/;
15637ed4
RG
446bad:
447 bp->b_flags |= B_ERROR;
448done:
449
519fb2b7
RG
450 /*
451 * Correctly set the buf to indicate a completed xfer
452 */
453 bp->b_resid = bp->b_bcount;
15637ed4 454 biodone(bp);
4c45483e 455 return /*0*/;
15637ed4
RG
456}
457
519fb2b7
RG
458/*
459 * sdstart looks to see if there is a buf waiting for the device
460 * and that the device is not already busy. If both are true,
461 * It dequeues the buf and creates a scsi command to perform the
462 * transfer in the buf. The transfer request will call scsi_done
463 * on completion, which will in turn call this routine again
464 * so that the next queued transfer is performed.
465 * The bufs are queued by the strategy routine (sdstrategy)
466 *
467 * This routine is also called after other non-queued requests
468 * have been made of the scsi driver, to ensure that the queue
469 * continues to be drained.
470 *
471 * must be called at the correct (highish) spl level
472 * sdstart() is called at SPLSD from sdstrategy and scsi_done
473 */
474void
15637ed4 475sdstart(unit)
519fb2b7 476 u_int32 unit;
15637ed4 477{
519fb2b7
RG
478 register struct sd_data *sd = sd_data[unit];
479 register struct scsi_link *sc_link = sd->sc_link;
480 struct buf *bp = 0;
481 struct buf *dp;
482 struct scsi_rw_big cmd;
483 u_int32 blkno, nblk;
484 struct partition *p;
485
486 SC_DEBUG(sc_link, SDEV_DB2, ("sdstart "));
487 /*
488 * Check if the device has room for another command
489 */
490 while (sc_link->opennings) {
15637ed4 491
519fb2b7
RG
492 /*
493 * there is excess capacity, but a special waits
494 * It'll need the adapter as soon as we clear out of the
495 * way and let it run (user level wait).
496 */
497 if (sc_link->flags & SDEV_WAITING) {
498 return;
499 }
500 /*
501 * See if there is a buf with work for us to do..
502 */
503 dp = &sd->buf_queue;
504 if ((bp = dp->b_actf) == NULL) { /* yes, an assign */
505 return;
506 }
507 dp->b_actf = bp->av_forw;
15637ed4 508
519fb2b7
RG
509 /*
510 * If the device has become invalid, abort all the
511 * reads and writes until all files have been closed and
512 * re-openned
513 */
514 if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
515 sd->flags &= ~SDHAVELABEL;
516 goto bad;
517 }
518 /*
519 * We have a buf, now we know we are going to go through
520 * With this thing..
521 *
522 * First, translate the block to absolute
523 */
524 p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
525 blkno = bp->b_blkno + p->p_offset;
526 nblk = (bp->b_bcount + 511) >> 9;
d4284689 527
519fb2b7
RG
528 /*
529 * Fill out the scsi command
530 */
531 bzero(&cmd, sizeof(cmd));
532 cmd.op_code = (bp->b_flags & B_READ)
533 ? READ_BIG : WRITE_BIG;
fde1aeb2 534 cmd.addr_3 = (blkno & 0xff000000UL) >> 24;
519fb2b7
RG
535 cmd.addr_2 = (blkno & 0xff0000) >> 16;
536 cmd.addr_1 = (blkno & 0xff00) >> 8;
537 cmd.addr_0 = blkno & 0xff;
538 cmd.length2 = (nblk & 0xff00) >> 8;
539 cmd.length1 = (nblk & 0xff);
540 /*
541 * Call the routine that chats with the adapter.
542 * Note: we cannot sleep as we may be an interrupt
543 */
544 if (scsi_scsi_cmd(sc_link,
545 (struct scsi_generic *) &cmd,
d4284689 546 sizeof(cmd),
519fb2b7 547 (u_char *) bp->b_un.b_addr,
d4284689 548 bp->b_bcount,
519fb2b7 549 SD_RETRIES,
d4284689
RG
550 10000,
551 bp,
519fb2b7
RG
552 SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
553 SCSI_DATA_IN : SCSI_DATA_OUT))
554 == SUCCESSFULLY_QUEUED) {
555 sdqueues++;
556 } else {
d4284689 557bad:
519fb2b7
RG
558 printf("sd%d: oops not queued", unit);
559 bp->b_error = EIO;
560 bp->b_flags |= B_ERROR;
561 biodone(bp);
562 }
15637ed4 563 }
15637ed4
RG
564}
565
519fb2b7
RG
566/*
567 * Perform special action on behalf of the user
568 * Knows about the internals of this device
569 */
570errval
15637ed4
RG
571sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
572{
519fb2b7
RG
573 /* struct sd_cmd_buf *args; */
574 errval error = 0;
15637ed4
RG
575 unsigned char unit, part;
576 register struct sd_data *sd;
577
519fb2b7
RG
578 /*
579 * Find the device that the user is talking about
580 */
15637ed4
RG
581 unit = UNIT(dev);
582 part = PARTITION(dev);
d4284689 583 sd = sd_data[unit];
519fb2b7
RG
584 SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd));
585
586 /*
587 * If the device is not valid.. abandon ship
588 */
589 if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED))
590 return (EIO);
591 switch (cmd) {
15637ed4
RG
592
593 case DIOCSBAD:
519fb2b7 594 error = EINVAL;
15637ed4
RG
595 break;
596
597 case DIOCGDINFO:
519fb2b7
RG
598 *(struct disklabel *) addr = sd->disklabel;
599 break;
600
601 case DIOCGPART:
602 ((struct partinfo *) addr)->disklab = &sd->disklabel;
603 ((struct partinfo *) addr)->part =
604 &sd->disklabel.d_partitions[PARTITION(dev)];
15637ed4
RG
605 break;
606
519fb2b7
RG
607 case DIOCSDINFO:
608 if ((flag & FWRITE) == 0)
609 error = EBADF;
610 else
611 error = setdisklabel(&sd->disklabel,
612 (struct disklabel *)addr,
613 /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */ 0,
614#ifdef NetBSD
615 &sd->cpudisklabel
616#else
617 sd->dosparts
618#endif
619 );
620 if (error == 0) {
15637ed4
RG
621 sd->flags |= SDHAVELABEL;
622 }
519fb2b7 623 break;
15637ed4 624
519fb2b7 625 case DIOCWLABEL:
15637ed4 626 sd->flags &= ~SDWRITEPROT;
519fb2b7
RG
627 if ((flag & FWRITE) == 0)
628 error = EBADF;
629 else
630 sd->wlabel = *(boolean *) addr;
631 break;
15637ed4 632
519fb2b7 633 case DIOCWDINFO:
15637ed4 634 sd->flags &= ~SDWRITEPROT;
519fb2b7
RG
635 if ((flag & FWRITE) == 0)
636 error = EBADF;
637 else {
638 error = setdisklabel(&sd->disklabel,
639 (struct disklabel *)addr,
640 /*(sd->flags & SDHAVELABEL) ? sd->openparts : */ 0,
641#ifdef NetBSD
642 &sd->cpudisklabel
643#else
644 sd->dosparts
645#endif
646 );
647 if (!error) {
648 boolean wlab;
649
650 /* ok - write will succeed */
651 sd->flags |= SDHAVELABEL;
652
653 /* simulate opening partition 0 so write succeeds */
654 sd->openparts |= (1 << 0); /* XXX */
655 wlab = sd->wlabel;
656 sd->wlabel = 1;
657 error = writedisklabel(dev, sdstrategy,
658 &sd->disklabel,
659#ifdef NetBSD
660 &sd->cpudisklabel
661#else
662 sd->dosparts
663#endif
664 );
665 sd->wlabel = wlab;
666 }
667 }
668 break;
15637ed4
RG
669
670 default:
519fb2b7
RG
671 if (part == RAW_PART)
672 error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag);
673 else
674 error = ENOTTY;
15637ed4
RG
675 break;
676 }
519fb2b7 677 return error;
15637ed4
RG
678}
679
519fb2b7
RG
680/*
681 * Load the label information on the named device
682 */
683errval
684sdgetdisklabel(unsigned char unit)
15637ed4 685{
519fb2b7 686 char *errstring;
d4284689 687 struct sd_data *sd = sd_data[unit];
15637ed4 688
519fb2b7
RG
689 /*
690 * If the inflo is already loaded, use it
691 */
692 if (sd->flags & SDHAVELABEL)
693 return (ESUCCESS);
694
695 bzero(&sd->disklabel, sizeof(struct disklabel));
696 /*
697 * make partition 3 the whole disk in case of failure then get pdinfo
698 * for historical reasons, make part a same as raw part
699 */
15637ed4
RG
700 sd->disklabel.d_partitions[0].p_offset = 0;
701 sd->disklabel.d_partitions[0].p_size = sd->params.disksize;
702 sd->disklabel.d_partitions[RAW_PART].p_offset = 0;
703 sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize;
704 sd->disklabel.d_npartitions = MAXPARTITIONS;
519fb2b7 705 sd->disklabel.d_secsize = SECSIZE; /* as long as it's not 0 */
15637ed4
RG
706 sd->disklabel.d_ntracks = sd->params.heads;
707 sd->disklabel.d_nsectors = sd->params.sectors;
708 sd->disklabel.d_ncylinders = sd->params.cyls;
709 sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors;
519fb2b7 710 if (sd->disklabel.d_secpercyl == 0) {
15637ed4 711 sd->disklabel.d_secpercyl = 100;
519fb2b7 712 /* as long as it's not 0 - readdisklabel divides by it (?) */
15637ed4 713 }
519fb2b7
RG
714 /*
715 * Call the generic disklabel extraction routine
716 */
717 if (errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + 3),
718 sdstrategy,
719 &sd->disklabel,
720#ifdef NetBSD
721 &sd->cpudisklabel
722#else
723 sd->dosparts,
724 0,
725 0
726#endif
727 )) {
728 printf("sd%d: %s\n", unit, errstring);
729 return ENXIO;
15637ed4 730 }
519fb2b7
RG
731 sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
732 return ESUCCESS;
15637ed4
RG
733}
734
519fb2b7
RG
735/*
736 * Find out from the device what it's capacity is
737 */
738u_int32
15637ed4 739sd_size(unit, flags)
519fb2b7 740 int unit, flags;
15637ed4
RG
741{
742 struct scsi_read_cap_data rdcap;
743 struct scsi_read_capacity scsi_cmd;
519fb2b7 744 u_int32 size;
15637ed4 745
519fb2b7
RG
746 /*
747 * make up a scsi command and ask the scsi driver to do
748 * it for you.
749 */
15637ed4
RG
750 bzero(&scsi_cmd, sizeof(scsi_cmd));
751 scsi_cmd.op_code = READ_CAPACITY;
752
519fb2b7
RG
753 /*
754 * If the command works, interpret the result as a 4 byte
755 * number of blocks
756 */
757 if (scsi_scsi_cmd(sd_data[unit]->sc_link,
758 (struct scsi_generic *) &scsi_cmd,
759 sizeof(scsi_cmd),
760 (u_char *) & rdcap,
761 sizeof(rdcap),
762 SD_RETRIES,
763 2000,
764 NULL,
765 flags | SCSI_DATA_IN) != 0) {
bb8f9615 766 printf("sd%d: could not get size\n", unit);
519fb2b7 767 return (0);
15637ed4 768 } else {
519fb2b7 769 size = rdcap.addr_0 + 1;
15637ed4
RG
770 size += rdcap.addr_1 << 8;
771 size += rdcap.addr_2 << 16;
772 size += rdcap.addr_3 << 24;
773 }
519fb2b7 774 return (size);
15637ed4
RG
775}
776
519fb2b7
RG
777/*
778 * Tell the device to map out a defective block
779 */
780errval
781sd_reassign_blocks(unit, block)
782 int unit, block;
15637ed4 783{
519fb2b7
RG
784 struct scsi_reassign_blocks scsi_cmd;
785 struct scsi_reassign_blocks_data rbdata;
15637ed4
RG
786
787 bzero(&scsi_cmd, sizeof(scsi_cmd));
788 bzero(&rbdata, sizeof(rbdata));
789 scsi_cmd.op_code = REASSIGN_BLOCKS;
790
791 rbdata.length_msb = 0;
792 rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
793 rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff);
794 rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff);
519fb2b7
RG
795 rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
796 rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff);
797
798 return (scsi_scsi_cmd(sd_data[unit]->sc_link,
799 (struct scsi_generic *) &scsi_cmd,
800 sizeof(scsi_cmd),
801 (u_char *) & rbdata,
802 sizeof(rbdata),
803 SD_RETRIES,
804 5000,
805 NULL,
806 SCSI_DATA_OUT));
15637ed4 807}
15637ed4
RG
808#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
809
519fb2b7
RG
810/*
811 * Get the scsi driver to send a full inquiry to the
812 * device and use the results to fill out the disk
813 * parameter structure.
814 */
815errval
816sd_get_parms(unit, flags)
817 int unit, flags;
15637ed4 818{
d4284689 819 struct sd_data *sd = sd_data[unit];
15637ed4 820 struct disk_parms *disk_parms = &sd->params;
519fb2b7
RG
821 struct scsi_mode_sense scsi_cmd;
822 struct scsi_mode_sense_data {
823 struct scsi_mode_header header;
824 struct blk_desc blk_desc;
825 union disk_pages pages;
826 } scsi_sense;
827 u_int32 sectors;
828
829 /*
830 * First check if we have it all loaded
831 */
46d39670 832 if (sd->sc_link->flags & SDEV_MEDIA_LOADED)
519fb2b7
RG
833 return 0;
834
835 /*
836 * do a "mode sense page 4"
837 */
15637ed4
RG
838 bzero(&scsi_cmd, sizeof(scsi_cmd));
839 scsi_cmd.op_code = MODE_SENSE;
869c4419 840 scsi_cmd.page = 4;
15637ed4 841 scsi_cmd.length = 0x20;
519fb2b7
RG
842 /*
843 * If the command worked, use the results to fill out
844 * the parameter structure
845 */
846 if (scsi_scsi_cmd(sd->sc_link,
847 (struct scsi_generic *) &scsi_cmd,
848 sizeof(scsi_cmd),
849 (u_char *) & scsi_sense,
850 sizeof(scsi_sense),
851 SD_RETRIES,
852 2000,
853 NULL,
854 flags | SCSI_DATA_IN) != 0) {
855
d4284689
RG
856 printf("sd%d could not mode sense (4).", unit);
857 printf(" Using ficticious geometry\n");
98639498
RG
858 /*
859 * use adaptec standard ficticious geometry
d4284689
RG
860 * this depends on which controller (e.g. 1542C is
861 * different. but we have to put SOMETHING here..)
98639498 862 */
15637ed4
RG
863 sectors = sd_size(unit, flags);
864 disk_parms->heads = 64;
865 disk_parms->sectors = 32;
519fb2b7 866 disk_parms->cyls = sectors / (64 * 32);
15637ed4 867 disk_parms->secsiz = SECSIZE;
98639498 868 disk_parms->disksize = sectors;
519fb2b7 869 } else {
d4284689 870
519fb2b7
RG
871 SC_DEBUG(sd->sc_link, SDEV_DB3,
872 ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
15637ed4
RG
873 _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2),
874 scsi_sense.pages.rigid_geometry.nheads,
875 b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp),
876 b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc),
519fb2b7
RG
877 b2tol(scsi_sense.pages.rigid_geometry.land_zone)));
878
879 /*
880 * KLUDGE!!(for zone recorded disks)
881 * give a number of sectors so that sec * trks * cyls
882 * is <= disk_size
883 * can lead to wasted space! THINK ABOUT THIS !
884 */
15637ed4
RG
885 disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads;
886 disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2);
519fb2b7 887 disk_parms->secsiz = _3btol(scsi_sense.blk_desc.blklen);
15637ed4
RG
888
889 sectors = sd_size(unit, flags);
98639498 890 disk_parms->disksize = sectors;
4d486ab8
AS
891 /* Check if none of these values are zero */
892 if(disk_parms->heads && disk_parms->cyls) {
893 sectors /= (disk_parms->heads * disk_parms->cyls);
894 }
895 else {
896 /* set it to something reasonable */
897 sectors = 32;
898 disk_parms->heads = 64;
899 disk_parms->cyls = sectors / (64 * 32);
900 }
519fb2b7 901 disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */
15637ed4 902 }
519fb2b7
RG
903 sd->sc_link->flags |= SDEV_MEDIA_LOADED;
904 return 0;
15637ed4
RG
905}
906
519fb2b7
RG
907int
908sdsize(dev_t dev)
15637ed4 909{
519fb2b7 910 u_int32 unit = UNIT(dev), part = PARTITION(dev), val;
d4284689 911 struct sd_data *sd;
15637ed4 912
519fb2b7
RG
913 if (unit >= NSD)
914 return -1;
d4284689 915
519fb2b7
RG
916 sd = sd_data[unit];
917 if (!sd)
918 return -1;
919 if ((sd->flags & SDINIT) == 0)
920 return -1;
921 if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) {
922 val = sdopen(MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
923 if (val != 0)
924 return -1;
15637ed4 925 }
519fb2b7
RG
926 if (sd->flags & SDWRITEPROT)
927 return -1;
15637ed4 928
519fb2b7 929 return (int)sd->disklabel.d_partitions[part].p_size;
15637ed4
RG
930}
931
519fb2b7
RG
932/*
933 * dump all of physical memory into the partition specified, starting
934 * at offset 'dumplo' into the partition.
935 */
936errval
937sddump(dev_t dev)
938{ /* dump core after a system crash */
98639498 939 register struct sd_data *sd; /* disk unit to do the IO */
519fb2b7
RG
940 int32 num; /* number of sectors to write */
941 u_int32 unit, part;
942 int32 blkoff, blknum, blkcnt = MAXTRANSFER;
943 int32 nblocks;
98639498 944 char *addr;
519fb2b7 945 struct scsi_rw_big cmd;
98639498 946 extern int Maxmem;
519fb2b7 947 static int sddoingadump = 0;
16656850
RG
948 extern caddr_t CADDR1; /* map the page we are about to write, here */
949 extern struct pte *CMAP1;
519fb2b7
RG
950 struct scsi_xfer *xs = &sx;
951 errval retval;
952 int c;
98639498 953
519fb2b7 954 addr = (char *) 0; /* starting address */
98639498
RG
955
956 /* toss any characters present prior to dump */
519fb2b7 957 while ((c = sgetc(1)) && (c != 0x100)); /*syscons and pccons differ */
98639498
RG
958
959 /* size of memory to dump */
960 num = Maxmem;
519fb2b7
RG
961 unit = UNIT(dev); /* eventually support floppies? */
962 part = PARTITION(dev); /* file system */
98639498 963 /* check for acceptable drive number */
519fb2b7 964 if (unit >= NSD)
16656850 965 return (ENXIO);
98639498 966
d4284689 967 sd = sd_data[unit];
519fb2b7
RG
968 if (!sd)
969 return (ENXIO);
98639498 970 /* was it ever initialized etc. ? */
519fb2b7
RG
971 if (!(sd->flags & SDINIT))
972 return (ENXIO);
973 if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED)
974 return (ENXIO);
975 if (sd->flags & SDWRITEPROT)
976 return (ENXIO);
a0becc21 977
98639498 978 /* Convert to disk sectors */
519fb2b7 979 num = (u_int32) num * NBPG / sd->disklabel.d_secsize;
a0becc21 980
98639498 981 /* check if controller active */
519fb2b7
RG
982 if (sddoingadump)
983 return (EFAULT);
a0becc21 984
98639498
RG
985 nblocks = sd->disklabel.d_partitions[part].p_size;
986 blkoff = sd->disklabel.d_partitions[part].p_offset;
a0becc21 987
98639498
RG
988 /* check transfer bounds against partition size */
989 if ((dumplo < 0) || ((dumplo + num) > nblocks))
519fb2b7 990 return (EINVAL);
98639498 991
519fb2b7 992 sddoingadump = 1;
98639498
RG
993
994 blknum = dumplo + blkoff;
519fb2b7 995 while (num > 0) {
16656850 996 *(int *)CMAP1 =
9ad9c554 997 PG_V | PG_KW | trunc_page(addr);
16656850 998 tlbflush();
519fb2b7
RG
999 /*
1000 * Fill out the scsi command
1001 */
98639498 1002 bzero(&cmd, sizeof(cmd));
519fb2b7
RG
1003 cmd.op_code = WRITE_BIG;
1004 cmd.addr_3 = (blknum & 0xff000000) >> 24;
1005 cmd.addr_2 = (blknum & 0xff0000) >> 16;
1006 cmd.addr_1 = (blknum & 0xff00) >> 8;
1007 cmd.addr_0 = blknum & 0xff;
1008 cmd.length2 = (blkcnt & 0xff00) >> 8;
1009 cmd.length1 = (blkcnt & 0xff);
1010 /*
1011 * Fill out the scsi_xfer structure
1012 * Note: we cannot sleep as we may be an interrupt
1013 * don't use scsi_scsi_cmd() as it may want
1014 * to wait for an xs.
1015 */
98639498 1016 bzero(xs, sizeof(sx));
519fb2b7
RG
1017 xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE;
1018 xs->sc_link = sd->sc_link;
1019 xs->retries = SD_RETRIES;
1020 xs->timeout = 10000; /* 10000 millisecs for a disk ! */
1021 xs->cmd = (struct scsi_generic *) &cmd;
1022 xs->cmdlen = sizeof(cmd);
1023 xs->resid = blkcnt * 512;
1024 xs->error = XS_NOERROR;
1025 xs->bp = 0;
16656850 1026 xs->data = (u_char *) CADDR1;
519fb2b7
RG
1027 xs->datalen = blkcnt * 512;
1028
1029 /*
1030 * Pass all this info to the scsi driver.
1031 */
1032 retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
1033 switch (retval) {
1034 case SUCCESSFULLY_QUEUED:
1035 case HAD_ERROR:
1036 return (ENXIO); /* we said not to sleep! */
1037 case COMPLETE:
98639498
RG
1038 break;
1039 default:
519fb2b7 1040 return (ENXIO); /* we said not to sleep! */
98639498 1041 }
519fb2b7
RG
1042
1043 if ((unsigned) addr % (1024 * 1024) == 0)
1044 printf("%d ", num / 2048);
98639498 1045 /* update block count */
519fb2b7
RG
1046 num -= blkcnt;
1047 blknum += blkcnt;
1048 (int) addr += 512 * blkcnt;
98639498
RG
1049
1050 /* operator aborting dump? */
519fb2b7
RG
1051 if ((c = sgetc(1)) && (c != 0x100))
1052 return (EINTR);
98639498 1053 }
519fb2b7 1054 return (0);
98639498 1055}