This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.1'.
[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 *
c2714ef5 17 * $Id: sd.c,v 1.18.2.1 1994/03/15 03:54:29 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>
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
RG
185 unit,
186 dp->disksize / ((1024L * 1024L) / dp->secsiz),
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 */
418 }
15637ed4 419 opri = SPLSD();
519fb2b7 420 dp = &sd->buf_queue;
15637ed4 421
519fb2b7
RG
422 /*
423 * Place it in the queue of disk activities for this disk
424 */
15637ed4
RG
425 disksort(dp, bp);
426
519fb2b7
RG
427 /*
428 * Tell the device to get going on the transfer if it's
429 * not doing anything, otherwise just wait for completion
430 */
15637ed4
RG
431 sdstart(unit);
432
433 splx(opri);
4c45483e 434 return /*0*/;
15637ed4
RG
435bad:
436 bp->b_flags |= B_ERROR;
437done:
438
519fb2b7
RG
439 /*
440 * Correctly set the buf to indicate a completed xfer
441 */
442 bp->b_resid = bp->b_bcount;
15637ed4 443 biodone(bp);
4c45483e 444 return /*0*/;
15637ed4
RG
445}
446
519fb2b7
RG
447/*
448 * sdstart looks to see if there is a buf waiting for the device
449 * and that the device is not already busy. If both are true,
450 * It dequeues the buf and creates a scsi command to perform the
451 * transfer in the buf. The transfer request will call scsi_done
452 * on completion, which will in turn call this routine again
453 * so that the next queued transfer is performed.
454 * The bufs are queued by the strategy routine (sdstrategy)
455 *
456 * This routine is also called after other non-queued requests
457 * have been made of the scsi driver, to ensure that the queue
458 * continues to be drained.
459 *
460 * must be called at the correct (highish) spl level
461 * sdstart() is called at SPLSD from sdstrategy and scsi_done
462 */
463void
15637ed4 464sdstart(unit)
519fb2b7 465 u_int32 unit;
15637ed4 466{
519fb2b7
RG
467 register struct sd_data *sd = sd_data[unit];
468 register struct scsi_link *sc_link = sd->sc_link;
469 struct buf *bp = 0;
470 struct buf *dp;
471 struct scsi_rw_big cmd;
472 u_int32 blkno, nblk;
473 struct partition *p;
474
475 SC_DEBUG(sc_link, SDEV_DB2, ("sdstart "));
476 /*
477 * Check if the device has room for another command
478 */
479 while (sc_link->opennings) {
15637ed4 480
519fb2b7
RG
481 /*
482 * there is excess capacity, but a special waits
483 * It'll need the adapter as soon as we clear out of the
484 * way and let it run (user level wait).
485 */
486 if (sc_link->flags & SDEV_WAITING) {
487 return;
488 }
489 /*
490 * See if there is a buf with work for us to do..
491 */
492 dp = &sd->buf_queue;
493 if ((bp = dp->b_actf) == NULL) { /* yes, an assign */
494 return;
495 }
496 dp->b_actf = bp->av_forw;
15637ed4 497
519fb2b7
RG
498 /*
499 * If the device has become invalid, abort all the
500 * reads and writes until all files have been closed and
501 * re-openned
502 */
503 if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
504 sd->flags &= ~SDHAVELABEL;
505 goto bad;
506 }
507 /*
508 * We have a buf, now we know we are going to go through
509 * With this thing..
510 *
511 * First, translate the block to absolute
512 */
513 p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
514 blkno = bp->b_blkno + p->p_offset;
515 nblk = (bp->b_bcount + 511) >> 9;
d4284689 516
519fb2b7
RG
517 /*
518 * Fill out the scsi command
519 */
520 bzero(&cmd, sizeof(cmd));
521 cmd.op_code = (bp->b_flags & B_READ)
522 ? READ_BIG : WRITE_BIG;
fde1aeb2 523 cmd.addr_3 = (blkno & 0xff000000UL) >> 24;
519fb2b7
RG
524 cmd.addr_2 = (blkno & 0xff0000) >> 16;
525 cmd.addr_1 = (blkno & 0xff00) >> 8;
526 cmd.addr_0 = blkno & 0xff;
527 cmd.length2 = (nblk & 0xff00) >> 8;
528 cmd.length1 = (nblk & 0xff);
529 /*
530 * Call the routine that chats with the adapter.
531 * Note: we cannot sleep as we may be an interrupt
532 */
533 if (scsi_scsi_cmd(sc_link,
534 (struct scsi_generic *) &cmd,
d4284689 535 sizeof(cmd),
519fb2b7 536 (u_char *) bp->b_un.b_addr,
d4284689 537 bp->b_bcount,
519fb2b7 538 SD_RETRIES,
d4284689
RG
539 10000,
540 bp,
519fb2b7
RG
541 SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
542 SCSI_DATA_IN : SCSI_DATA_OUT))
543 == SUCCESSFULLY_QUEUED) {
544 sdqueues++;
545 } else {
d4284689 546bad:
519fb2b7
RG
547 printf("sd%d: oops not queued", unit);
548 bp->b_error = EIO;
549 bp->b_flags |= B_ERROR;
550 biodone(bp);
551 }
15637ed4 552 }
15637ed4
RG
553}
554
519fb2b7
RG
555/*
556 * Perform special action on behalf of the user
557 * Knows about the internals of this device
558 */
559errval
15637ed4
RG
560sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
561{
519fb2b7
RG
562 /* struct sd_cmd_buf *args; */
563 errval error = 0;
15637ed4
RG
564 unsigned char unit, part;
565 register struct sd_data *sd;
566
519fb2b7
RG
567 /*
568 * Find the device that the user is talking about
569 */
15637ed4
RG
570 unit = UNIT(dev);
571 part = PARTITION(dev);
d4284689 572 sd = sd_data[unit];
519fb2b7
RG
573 SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd));
574
575 /*
576 * If the device is not valid.. abandon ship
577 */
578 if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED))
579 return (EIO);
580 switch (cmd) {
15637ed4
RG
581
582 case DIOCSBAD:
519fb2b7 583 error = EINVAL;
15637ed4
RG
584 break;
585
586 case DIOCGDINFO:
519fb2b7
RG
587 *(struct disklabel *) addr = sd->disklabel;
588 break;
589
590 case DIOCGPART:
591 ((struct partinfo *) addr)->disklab = &sd->disklabel;
592 ((struct partinfo *) addr)->part =
593 &sd->disklabel.d_partitions[PARTITION(dev)];
15637ed4
RG
594 break;
595
519fb2b7
RG
596 case DIOCSDINFO:
597 if ((flag & FWRITE) == 0)
598 error = EBADF;
599 else
600 error = setdisklabel(&sd->disklabel,
601 (struct disklabel *)addr,
602 /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */ 0,
603#ifdef NetBSD
604 &sd->cpudisklabel
605#else
606 sd->dosparts
607#endif
608 );
609 if (error == 0) {
15637ed4
RG
610 sd->flags |= SDHAVELABEL;
611 }
519fb2b7 612 break;
15637ed4 613
519fb2b7 614 case DIOCWLABEL:
15637ed4 615 sd->flags &= ~SDWRITEPROT;
519fb2b7
RG
616 if ((flag & FWRITE) == 0)
617 error = EBADF;
618 else
619 sd->wlabel = *(boolean *) addr;
620 break;
15637ed4 621
519fb2b7 622 case DIOCWDINFO:
15637ed4 623 sd->flags &= ~SDWRITEPROT;
519fb2b7
RG
624 if ((flag & FWRITE) == 0)
625 error = EBADF;
626 else {
627 error = setdisklabel(&sd->disklabel,
628 (struct disklabel *)addr,
629 /*(sd->flags & SDHAVELABEL) ? sd->openparts : */ 0,
630#ifdef NetBSD
631 &sd->cpudisklabel
632#else
633 sd->dosparts
634#endif
635 );
636 if (!error) {
637 boolean wlab;
638
639 /* ok - write will succeed */
640 sd->flags |= SDHAVELABEL;
641
642 /* simulate opening partition 0 so write succeeds */
643 sd->openparts |= (1 << 0); /* XXX */
644 wlab = sd->wlabel;
645 sd->wlabel = 1;
646 error = writedisklabel(dev, sdstrategy,
647 &sd->disklabel,
648#ifdef NetBSD
649 &sd->cpudisklabel
650#else
651 sd->dosparts
652#endif
653 );
654 sd->wlabel = wlab;
655 }
656 }
657 break;
15637ed4
RG
658
659 default:
519fb2b7
RG
660 if (part == RAW_PART)
661 error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag);
662 else
663 error = ENOTTY;
15637ed4
RG
664 break;
665 }
519fb2b7 666 return error;
15637ed4
RG
667}
668
519fb2b7
RG
669/*
670 * Load the label information on the named device
671 */
672errval
673sdgetdisklabel(unsigned char unit)
15637ed4 674{
519fb2b7 675 char *errstring;
d4284689 676 struct sd_data *sd = sd_data[unit];
15637ed4 677
519fb2b7
RG
678 /*
679 * If the inflo is already loaded, use it
680 */
681 if (sd->flags & SDHAVELABEL)
682 return (ESUCCESS);
683
684 bzero(&sd->disklabel, sizeof(struct disklabel));
685 /*
686 * make partition 3 the whole disk in case of failure then get pdinfo
687 * for historical reasons, make part a same as raw part
688 */
15637ed4
RG
689 sd->disklabel.d_partitions[0].p_offset = 0;
690 sd->disklabel.d_partitions[0].p_size = sd->params.disksize;
691 sd->disklabel.d_partitions[RAW_PART].p_offset = 0;
692 sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize;
693 sd->disklabel.d_npartitions = MAXPARTITIONS;
519fb2b7 694 sd->disklabel.d_secsize = SECSIZE; /* as long as it's not 0 */
15637ed4
RG
695 sd->disklabel.d_ntracks = sd->params.heads;
696 sd->disklabel.d_nsectors = sd->params.sectors;
697 sd->disklabel.d_ncylinders = sd->params.cyls;
698 sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors;
519fb2b7 699 if (sd->disklabel.d_secpercyl == 0) {
15637ed4 700 sd->disklabel.d_secpercyl = 100;
519fb2b7 701 /* as long as it's not 0 - readdisklabel divides by it (?) */
15637ed4 702 }
519fb2b7
RG
703 /*
704 * Call the generic disklabel extraction routine
705 */
706 if (errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + 3),
707 sdstrategy,
708 &sd->disklabel,
709#ifdef NetBSD
710 &sd->cpudisklabel
711#else
712 sd->dosparts,
713 0,
714 0
715#endif
716 )) {
717 printf("sd%d: %s\n", unit, errstring);
718 return ENXIO;
15637ed4 719 }
519fb2b7
RG
720 sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
721 return ESUCCESS;
15637ed4
RG
722}
723
519fb2b7
RG
724/*
725 * Find out from the device what it's capacity is
726 */
727u_int32
15637ed4 728sd_size(unit, flags)
519fb2b7 729 int unit, flags;
15637ed4
RG
730{
731 struct scsi_read_cap_data rdcap;
732 struct scsi_read_capacity scsi_cmd;
519fb2b7 733 u_int32 size;
15637ed4 734
519fb2b7
RG
735 /*
736 * make up a scsi command and ask the scsi driver to do
737 * it for you.
738 */
15637ed4
RG
739 bzero(&scsi_cmd, sizeof(scsi_cmd));
740 scsi_cmd.op_code = READ_CAPACITY;
741
519fb2b7
RG
742 /*
743 * If the command works, interpret the result as a 4 byte
744 * number of blocks
745 */
746 if (scsi_scsi_cmd(sd_data[unit]->sc_link,
747 (struct scsi_generic *) &scsi_cmd,
748 sizeof(scsi_cmd),
749 (u_char *) & rdcap,
750 sizeof(rdcap),
751 SD_RETRIES,
752 2000,
753 NULL,
754 flags | SCSI_DATA_IN) != 0) {
bb8f9615 755 printf("sd%d: could not get size\n", unit);
519fb2b7 756 return (0);
15637ed4 757 } else {
519fb2b7 758 size = rdcap.addr_0 + 1;
15637ed4
RG
759 size += rdcap.addr_1 << 8;
760 size += rdcap.addr_2 << 16;
761 size += rdcap.addr_3 << 24;
762 }
519fb2b7 763 return (size);
15637ed4
RG
764}
765
519fb2b7
RG
766/*
767 * Tell the device to map out a defective block
768 */
769errval
770sd_reassign_blocks(unit, block)
771 int unit, block;
15637ed4 772{
519fb2b7
RG
773 struct scsi_reassign_blocks scsi_cmd;
774 struct scsi_reassign_blocks_data rbdata;
15637ed4
RG
775
776 bzero(&scsi_cmd, sizeof(scsi_cmd));
777 bzero(&rbdata, sizeof(rbdata));
778 scsi_cmd.op_code = REASSIGN_BLOCKS;
779
780 rbdata.length_msb = 0;
781 rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
782 rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff);
783 rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff);
519fb2b7
RG
784 rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
785 rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff);
786
787 return (scsi_scsi_cmd(sd_data[unit]->sc_link,
788 (struct scsi_generic *) &scsi_cmd,
789 sizeof(scsi_cmd),
790 (u_char *) & rbdata,
791 sizeof(rbdata),
792 SD_RETRIES,
793 5000,
794 NULL,
795 SCSI_DATA_OUT));
15637ed4 796}
15637ed4
RG
797#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
798
519fb2b7
RG
799/*
800 * Get the scsi driver to send a full inquiry to the
801 * device and use the results to fill out the disk
802 * parameter structure.
803 */
804errval
805sd_get_parms(unit, flags)
806 int unit, flags;
15637ed4 807{
d4284689 808 struct sd_data *sd = sd_data[unit];
15637ed4 809 struct disk_parms *disk_parms = &sd->params;
519fb2b7
RG
810 struct scsi_mode_sense scsi_cmd;
811 struct scsi_mode_sense_data {
812 struct scsi_mode_header header;
813 struct blk_desc blk_desc;
814 union disk_pages pages;
815 } scsi_sense;
816 u_int32 sectors;
817
818 /*
819 * First check if we have it all loaded
820 */
46d39670 821 if (sd->sc_link->flags & SDEV_MEDIA_LOADED)
519fb2b7
RG
822 return 0;
823
824 /*
825 * do a "mode sense page 4"
826 */
15637ed4
RG
827 bzero(&scsi_cmd, sizeof(scsi_cmd));
828 scsi_cmd.op_code = MODE_SENSE;
869c4419 829 scsi_cmd.page = 4;
15637ed4 830 scsi_cmd.length = 0x20;
519fb2b7
RG
831 /*
832 * If the command worked, use the results to fill out
833 * the parameter structure
834 */
835 if (scsi_scsi_cmd(sd->sc_link,
836 (struct scsi_generic *) &scsi_cmd,
837 sizeof(scsi_cmd),
838 (u_char *) & scsi_sense,
839 sizeof(scsi_sense),
840 SD_RETRIES,
841 2000,
842 NULL,
843 flags | SCSI_DATA_IN) != 0) {
844
d4284689
RG
845 printf("sd%d could not mode sense (4).", unit);
846 printf(" Using ficticious geometry\n");
98639498
RG
847 /*
848 * use adaptec standard ficticious geometry
d4284689
RG
849 * this depends on which controller (e.g. 1542C is
850 * different. but we have to put SOMETHING here..)
98639498 851 */
15637ed4
RG
852 sectors = sd_size(unit, flags);
853 disk_parms->heads = 64;
854 disk_parms->sectors = 32;
519fb2b7 855 disk_parms->cyls = sectors / (64 * 32);
15637ed4 856 disk_parms->secsiz = SECSIZE;
98639498 857 disk_parms->disksize = sectors;
519fb2b7 858 } else {
d4284689 859
519fb2b7
RG
860 SC_DEBUG(sd->sc_link, SDEV_DB3,
861 ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
15637ed4
RG
862 _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2),
863 scsi_sense.pages.rigid_geometry.nheads,
864 b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp),
865 b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc),
519fb2b7
RG
866 b2tol(scsi_sense.pages.rigid_geometry.land_zone)));
867
868 /*
869 * KLUDGE!!(for zone recorded disks)
870 * give a number of sectors so that sec * trks * cyls
871 * is <= disk_size
872 * can lead to wasted space! THINK ABOUT THIS !
873 */
15637ed4
RG
874 disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads;
875 disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2);
519fb2b7 876 disk_parms->secsiz = _3btol(scsi_sense.blk_desc.blklen);
15637ed4
RG
877
878 sectors = sd_size(unit, flags);
98639498 879 disk_parms->disksize = sectors;
c2714ef5 880 /* Check if none of these values are zero */
881 if(disk_parms->heads && disk_parms->cyls) {
882 sectors /= (disk_parms->heads * disk_parms->cyls);
883 }
884 else {
885 /* set it to something reasonable */
886 sectors = 32;
887 disk_parms->heads = 64;
888 disk_parms->cyls = sectors / (64 * 32);
889 }
519fb2b7 890 disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */
15637ed4 891 }
519fb2b7
RG
892 sd->sc_link->flags |= SDEV_MEDIA_LOADED;
893 return 0;
15637ed4
RG
894}
895
519fb2b7
RG
896int
897sdsize(dev_t dev)
15637ed4 898{
519fb2b7 899 u_int32 unit = UNIT(dev), part = PARTITION(dev), val;
d4284689 900 struct sd_data *sd;
15637ed4 901
519fb2b7
RG
902 if (unit >= NSD)
903 return -1;
d4284689 904
519fb2b7
RG
905 sd = sd_data[unit];
906 if (!sd)
907 return -1;
908 if ((sd->flags & SDINIT) == 0)
909 return -1;
910 if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) {
911 val = sdopen(MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
912 if (val != 0)
913 return -1;
15637ed4 914 }
519fb2b7
RG
915 if (sd->flags & SDWRITEPROT)
916 return -1;
15637ed4 917
519fb2b7 918 return (int)sd->disklabel.d_partitions[part].p_size;
15637ed4
RG
919}
920
519fb2b7
RG
921/*
922 * dump all of physical memory into the partition specified, starting
923 * at offset 'dumplo' into the partition.
924 */
925errval
926sddump(dev_t dev)
927{ /* dump core after a system crash */
98639498 928 register struct sd_data *sd; /* disk unit to do the IO */
519fb2b7
RG
929 int32 num; /* number of sectors to write */
930 u_int32 unit, part;
931 int32 blkoff, blknum, blkcnt = MAXTRANSFER;
932 int32 nblocks;
98639498 933 char *addr;
519fb2b7 934 struct scsi_rw_big cmd;
98639498 935 extern int Maxmem;
519fb2b7 936 static int sddoingadump = 0;
16656850
RG
937 extern caddr_t CADDR1; /* map the page we are about to write, here */
938 extern struct pte *CMAP1;
519fb2b7
RG
939 struct scsi_xfer *xs = &sx;
940 errval retval;
941 int c;
98639498 942
519fb2b7 943 addr = (char *) 0; /* starting address */
98639498
RG
944
945 /* toss any characters present prior to dump */
519fb2b7 946 while ((c = sgetc(1)) && (c != 0x100)); /*syscons and pccons differ */
98639498
RG
947
948 /* size of memory to dump */
949 num = Maxmem;
519fb2b7
RG
950 unit = UNIT(dev); /* eventually support floppies? */
951 part = PARTITION(dev); /* file system */
98639498 952 /* check for acceptable drive number */
519fb2b7 953 if (unit >= NSD)
16656850 954 return (ENXIO);
98639498 955
d4284689 956 sd = sd_data[unit];
519fb2b7
RG
957 if (!sd)
958 return (ENXIO);
98639498 959 /* was it ever initialized etc. ? */
519fb2b7
RG
960 if (!(sd->flags & SDINIT))
961 return (ENXIO);
962 if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED)
963 return (ENXIO);
964 if (sd->flags & SDWRITEPROT)
965 return (ENXIO);
a0becc21 966
98639498 967 /* Convert to disk sectors */
519fb2b7 968 num = (u_int32) num * NBPG / sd->disklabel.d_secsize;
a0becc21 969
98639498 970 /* check if controller active */
519fb2b7
RG
971 if (sddoingadump)
972 return (EFAULT);
a0becc21 973
98639498
RG
974 nblocks = sd->disklabel.d_partitions[part].p_size;
975 blkoff = sd->disklabel.d_partitions[part].p_offset;
a0becc21 976
98639498
RG
977 /* check transfer bounds against partition size */
978 if ((dumplo < 0) || ((dumplo + num) > nblocks))
519fb2b7 979 return (EINVAL);
98639498 980
519fb2b7 981 sddoingadump = 1;
98639498
RG
982
983 blknum = dumplo + blkoff;
519fb2b7 984 while (num > 0) {
16656850 985 *(int *)CMAP1 =
9ad9c554 986 PG_V | PG_KW | trunc_page(addr);
16656850 987 tlbflush();
519fb2b7
RG
988 /*
989 * Fill out the scsi command
990 */
98639498 991 bzero(&cmd, sizeof(cmd));
519fb2b7
RG
992 cmd.op_code = WRITE_BIG;
993 cmd.addr_3 = (blknum & 0xff000000) >> 24;
994 cmd.addr_2 = (blknum & 0xff0000) >> 16;
995 cmd.addr_1 = (blknum & 0xff00) >> 8;
996 cmd.addr_0 = blknum & 0xff;
997 cmd.length2 = (blkcnt & 0xff00) >> 8;
998 cmd.length1 = (blkcnt & 0xff);
999 /*
1000 * Fill out the scsi_xfer structure
1001 * Note: we cannot sleep as we may be an interrupt
1002 * don't use scsi_scsi_cmd() as it may want
1003 * to wait for an xs.
1004 */
98639498 1005 bzero(xs, sizeof(sx));
519fb2b7
RG
1006 xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE;
1007 xs->sc_link = sd->sc_link;
1008 xs->retries = SD_RETRIES;
1009 xs->timeout = 10000; /* 10000 millisecs for a disk ! */
1010 xs->cmd = (struct scsi_generic *) &cmd;
1011 xs->cmdlen = sizeof(cmd);
1012 xs->resid = blkcnt * 512;
1013 xs->error = XS_NOERROR;
1014 xs->bp = 0;
16656850 1015 xs->data = (u_char *) CADDR1;
519fb2b7
RG
1016 xs->datalen = blkcnt * 512;
1017
1018 /*
1019 * Pass all this info to the scsi driver.
1020 */
1021 retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
1022 switch (retval) {
1023 case SUCCESSFULLY_QUEUED:
1024 case HAD_ERROR:
1025 return (ENXIO); /* we said not to sleep! */
1026 case COMPLETE:
98639498
RG
1027 break;
1028 default:
519fb2b7 1029 return (ENXIO); /* we said not to sleep! */
98639498 1030 }
519fb2b7
RG
1031
1032 if ((unsigned) addr % (1024 * 1024) == 0)
1033 printf("%d ", num / 2048);
98639498 1034 /* update block count */
519fb2b7
RG
1035 num -= blkcnt;
1036 blknum += blkcnt;
1037 (int) addr += 512 * blkcnt;
98639498
RG
1038
1039 /* operator aborting dump? */
519fb2b7
RG
1040 if ((c = sgetc(1)) && (c != 0x100))
1041 return (EINTR);
98639498 1042 }
519fb2b7 1043 return (0);
98639498 1044}