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