|
|
1.1 root 1: /*
2: * Copyright (c) 1994 Shantanu Goel
3: * All Rights Reserved.
4: *
5: * Permission to use, copy, modify and distribute this software and its
6: * documentation is hereby granted, provided that both the copyright
7: * notice and this permission notice appear in all copies of the
8: * software, derivative works or modified versions, and any portions
9: * thereof, and that both notices appear in supporting documentation.
10: *
11: * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
12: * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
13: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
14: *
15: * MODIFIED BY KEVIN T. VAN MAREN, University of Utah, CSL
16: * Copyright (c) 1996, University of Utah, CSL
17: *
18: * Uses a 'unified' partition code with the SCSI driver.
19: * Reading/Writing disklabels through the kernel is NOT recommended.
20: * (The preferred method is through the raw device (wd0), with no
21: * open partitions). setdisklabel() should work for the in-core
22: * fudged disklabel, but will not change the partitioning. The driver
23: * *never* sees the disklabel on the disk.
24: *
25: */
26:
27:
28: #include <hd.h>
29: #if NHD > 0 && !defined(LINUX_DEV)
30: /*
31: * Hard disk driver.
32: *
33: * Supports:
34: * 1 controller and 2 drives.
35: * Arbitrarily sized read/write requests.
36: * Misaligned requests.
37: * Multiple sector transfer mode (not tested extensively).
38: *
39: * TODO:
40: * 1) Real probe routines for controller and drives.
41: * 2) Support for multiple controllers. The driver does
42: * not assume a single controller since all functions
43: * take the controller and/or device structure as an
44: * argument, however the probe routines limit the
45: * number of controllers and drives to 1 and 2 respectively.
46: *
47: * Shantanu Goel ([email protected])
48: */
49: #include <sys/types.h>
50: #include <sys/ioctl.h>
51: #include "vm_param.h"
52: #include <kern/time_out.h>
53: #include <vm/vm_kern.h>
54: #include <vm/pmap.h>
55: #include <device/param.h>
56: #include <device/buf.h>
57: #include <device/errno.h>
58: #include <device/device_types.h>
59: #include <device/disk_status.h>
60: #include <chips/busses.h>
61: #include <i386/machspl.h>
62: #include <i386/pio.h>
63: #include <i386at/cram.h>
64: #include <i386at/disk.h>
65: #include <i386at/nhdreg.h>
66:
67: #include <scsi/rz_labels.h>
68:
69:
70: /* this is for the partition code */
71: typedef struct ide_driver_info {
72: dev_t dev;
73: /* struct buf *bp; */
74: int sectorsize;
75: } ide_driver_info;
76:
77: #define MAX_IDE_PARTS 32 /* max partitions per drive */
78: static char *drive_name[4]={"wd0: ","wd1: ","xxx ","yyy "};
79:
80: /*
81: * XXX: This will have to be fixed for controllers that
82: * can support upto 4 drives.
83: */
84: #define NDRIVES_PER_HDC 2
85: #define NHDC ((NHD + NDRIVES_PER_HDC - 1) / NDRIVES_PER_HDC)
86:
87: #define b_cylin b_resid
88:
89: #define B_ABS B_MD1
90: #define B_IDENTIFY (B_MD1 << 1)
91:
92: /* shift right SLICE_BITS + PARTITION_BITS. Note: 2^10 = 1024 sub-parts */
93: #define hdunit(dev) (((dev) >> 10) & 3)
94: #define hdpart(dev) ((dev) & 0x3ff)
95:
96: #define MAX_RETRIES 12 /* maximum number of retries */
97: #define OP_TIMEOUT 7 /* time to wait (secs) for an operation */
98:
99: /*
100: * Autoconfiguration stuff.
101: */
102: struct bus_ctlr *hdminfo[NHDC];
103: struct bus_device *hddinfo[NHD];
104: int hdstd[] = { 0 };
105: int hdprobe(), hdslave(), hdstrategy();
106: void hdattach();
107: struct bus_driver hddriver = {
108: hdprobe, hdslave, hdattach, 0, hdstd, "hd", hddinfo, "hdc", hdminfo, 0
109: };
110:
111: /*
112: * BIOS geometry.
113: */
114: struct hdbios {
115: int bg_ncyl; /* cylinders/unit */
116: int bg_ntrk; /* tracks/cylinder */
117: int bg_precomp; /* write precomp cylinder */
118: int bg_nsect; /* sectors/track */
119: } hdbios[NHD];
120:
121: /*
122: * Controller state.
123: */
124: struct hdcsoftc {
125: int sc_state; /* transfer fsm */
126: caddr_t sc_addr; /* buffer address */
127: int sc_resid; /* amount left to transfer */
128: int sc_amt; /* amount currently being transferred */
129: int sc_cnt; /* amount transferred per interrupt */
130: int sc_sn; /* sector number */
131: int sc_tn; /* track number */
132: int sc_cn; /* cylinder number */
133: int sc_recalerr; /* # recalibration errors */
134: int sc_ioerr; /* # i/o errors */
135: int sc_wticks; /* watchdog */
136: caddr_t sc_buf; /* buffer for unaligned requests */
137: } hdcsoftc[NHDC];
138:
139: /*
140: * Transfer states.
141: */
142: #define IDLE 0 /* controller is idle */
143: #define SETPARAM 1 /* set disk parameters */
144: #define SETPARAMDONE 2 /* set parameters done */
145: #define RESTORE 3 /* recalibrate drive */
146: #define RESTOREDONE 4 /* recalibrate done */
147: #define TRANSFER 5 /* perform I/O transfer */
148: #define TRANSFERDONE 6 /* transfer done */
149: #define IDENTIFY 7 /* get drive info */
150: #define IDENTIFYDONE 8 /* get drive info done */
151: #define SETMULTI 9 /* set multiple mode count */
152: #define SETMULTIDONE 10 /* set multiple mode count done */
153:
154: /*
155: * Drive state.
156: */
157: struct hdsoftc {
158: int sc_flags;
159: #define HDF_SETPARAM 0x001 /* set drive parameters before I/O operation */
160: #define HDF_RESTORE 0x002 /* drive needs recalibration */
161: #define HDF_WANT 0x004 /* some one is waiting for drive */
162: #define HDF_UNALIGNED 0x008 /* request is not a multiple of sector size */
163: #define HDF_SETMULTI 0x010 /* set multiple count before I/O operation */
164: #define HDF_MULTIDONE 0x020 /* multicnt field is valid */
165: #define HDF_IDENTDONE 0x040 /* identify command done */
166: #define HDF_LBA 0x080 /* use LBA mode */
167: int sc_multicnt; /* current multiple count */
168: int sc_abssn; /* absolute sector number (for {RD,WR}ABS) */
169: int sc_abscnt; /* absolute sector count */
170: int sc_openpart; /* bit mask of open partitions */
171: struct hdident sc_id; /* info returned by identify */
172: } hdsoftc[NHD];
173:
174: struct buf hdtab[NHDC]; /* controller queues */
175: struct buf hdutab[NHD]; /* drive queues */
176: struct disklabel hdlabel[NHD]; /* disklabels -- incorrect info! */
177: struct diskpart array[NHD*MAX_IDE_PARTS]; /* partition info */
178:
179: /*
180: * To enable multiple mode,
181: * set this, recompile, and reboot the machine.
182: */
183: int hdenmulti = 0;
184:
185: char *hderrchk();
186: struct buf *geteblk();
187: int hdwstart = 0;
188: void hdwatch();
189:
190: /*
191: * Probe for a controller.
192: */
193: int
194: hdprobe(xxx, um)
195: int xxx;
196: struct bus_ctlr *um;
197: {
198: struct hdcsoftc *hdc;
199:
200: if (um->unit >= NHDC) {
201: printf("hdc%d: not configured\n", um->unit);
202: return (0);
203: }
204: if (um->unit > 0) { /* XXX: only 1 controller */
205:
206: printf("nhd:probe for 2+ controllers -- not implemented\n");
207: return (0);
208: }
209:
210: /*
211: * XXX: need real probe
212: */
213: hdc = &hdcsoftc[um->unit];
214: if (!hdc->sc_buf)
215: kmem_alloc(kernel_map,
216: (vm_offset_t *)&hdc->sc_buf, I386_PGBYTES);
217: take_ctlr_irq(um);
218: return (1);
219: }
220:
221: /*
222: * Probe for a drive.
223: */
224: int
225: hdslave(ui)
226: struct bus_device *ui;
227: {
228: int type;
229:
230: if (ui->unit >= NHD) {
231: printf("hd%d: not configured\n", ui->unit);
232: return (0);
233: }
234: if (ui->unit > 1) /* XXX: only 2 drives */
235: return (0);
236:
237: /*
238: * Find out if drive exists by reading CMOS.
239: */
240: outb(CMOS_ADDR, 0x12);
241: type = inb(CMOS_DATA);
242: if (ui->unit == 0)
243: type >>= 4;
244: type &= 0x0f;
245: return (type);
246: }
247:
248: /*
249: * Attach a drive to the system.
250: */
251: void
252: hdattach(ui)
253: struct bus_device *ui;
254: {
255: char *tbl;
256: unsigned n;
257: /* struct hdsoftc *sc = &hdsoftc[ui->unit]; */
258: struct disklabel *lp = &hdlabel[ui->unit];
259: struct hdbios *bg = &hdbios[ui->unit];
260:
261: /*
262: * Set up a temporary disklabel from BIOS parameters.
263: * The actual partition table will be read during open.
264: */
265: n = *(unsigned *)phystokv(ui->address);
266: tbl = (unsigned char *)phystokv((n & 0xffff) + ((n >> 12) & 0xffff0));
267: bg->bg_ncyl = *(unsigned short *)tbl;
268: bg->bg_ntrk = *(unsigned char *)(tbl + 2);
269: bg->bg_precomp = *(unsigned short *)(tbl + 5);
270: bg->bg_nsect = *(unsigned char *)(tbl + 14);
271: fudge_bsd_label(lp, DTYPE_ESDI, bg->bg_ncyl*bg->bg_ntrk*bg->bg_nsect,
272: bg->bg_ntrk, bg->bg_nsect, SECSIZE, 3);
273:
274: /* FORCE sector size to 512... */
275:
276: printf(": ntrak(heads) %d, ncyl %d, nsec %d, size %u MB",
277: lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors,
278: lp->d_secperunit * lp->d_secsize / (1024*1024));
279: }
280:
281: int
282: hdopen(dev, mode)
283: dev_t dev;
284: int mode;
285: {
286: int unit = hdunit(dev), part = hdpart(dev) /*, error */;
287: struct bus_device *ui;
288: struct hdsoftc *sc;
289: struct diskpart *label;
290:
291: if (unit >= NHD || (ui = hddinfo[unit]) == 0 || ui->alive == 0)
292: return (ENXIO);
293: if (!hdwstart) {
294: hdwstart++;
295: timeout(hdwatch, 0, hz);
296: }
297: sc = &hdsoftc[unit];
298: /* should this be changed so only gets called once, even if all
299: partitions are closed and re-opened? */
300: if (sc->sc_openpart == 0) {
301: hdinit(dev);
302: if (sc->sc_flags & HDF_LBA)
303: printf("hd%d: Using LBA mode\n", ui->unit);
304: }
305:
306: /* Note: should set a bit in the label structure to ensure that
307: aliasing prevents multiple instances to be opened. */
308: #if 0
309: if (part >= MAXPARTITIONS || lp->d_partitions[part].p_size == 0)
310: return (ENXIO);
311: #endif 0
312:
313: label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(dev));
314: if (!label)
315: return (ENXIO);
316:
317:
318: sc->sc_openpart |= 1 << part;
319: return (0);
320: }
321:
322: int
323: hdclose(dev)
324: dev_t dev;
325: {
326: int unit = hdunit(dev), s;
327: struct hdsoftc *sc = &hdsoftc[unit];
328:
329: sc->sc_openpart &= ~(1 << hdpart(dev));
330: if (sc->sc_openpart == 0) {
331: s = splbio();
332: while (hdutab[unit].b_active) {
333: sc->sc_flags |= HDF_WANT;
334: assert_wait((event_t)sc, FALSE);
335: thread_block((void (*)())0);
336: }
337: splx(s);
338: }
339: return (0);
340: }
341:
342: int
343: hdread(dev, ior)
344: dev_t dev;
345: io_req_t ior;
346: {
347: return (block_io(hdstrategy, minphys, ior));
348: }
349:
350: int
351: hdwrite(dev, ior)
352: dev_t dev;
353: io_req_t ior;
354: {
355: return (block_io(hdstrategy, minphys, ior));
356: }
357:
358: int
359: hdgetstat(dev, flavor, data, count)
360: dev_t dev;
361: dev_flavor_t flavor;
362: dev_status_t data;
363: mach_msg_type_number_t *count;
364: {
365: int unit = hdunit(dev), part = hdpart(dev);
366: struct hdsoftc *sc = &hdsoftc[unit];
367: struct disklabel *lp = &hdlabel[unit];
368: struct buf *bp;
369: struct diskpart *label;
370:
371: label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(dev));
372: switch (flavor) {
373:
374: case DEV_GET_SIZE:
375: if (label) {
376: data[DEV_GET_SIZE_DEVICE_SIZE] = (label->size * lp->d_secsize);
377: data[DEV_GET_SIZE_RECORD_SIZE] = lp->d_secsize;
378: *count = DEV_GET_SIZE_COUNT;
379: } else { /* Kevin: added checking here */
380: data[DEV_GET_SIZE_DEVICE_SIZE] = 0;
381: data[DEV_GET_SIZE_RECORD_SIZE] = 0;
382: *count = 0;
383: }
384: break;
385:
386: case DIOCGDINFO:
387: case DIOCGDINFO - (0x10 << 16):
388: dkgetlabel(lp, flavor, data, count);
389: break;
390:
391: case V_GETPARMS:
392: {
393: struct disk_parms *dp;
394: struct hdbios *bg = &hdbios[unit];
395:
396: if (*count < (sizeof(struct disk_parms) / sizeof(int)))
397: return (D_INVALID_OPERATION);
398: dp = (struct disk_parms *)data;
399: dp->dp_type = DPT_WINI;
400: dp->dp_heads = lp->d_ntracks;
401: dp->dp_cyls = lp->d_ncylinders;
402: dp->dp_sectors = lp->d_nsectors;
403: dp->dp_dosheads = bg->bg_ntrk;
404: dp->dp_doscyls = bg->bg_ncyl;
405: dp->dp_dossectors = bg->bg_nsect;
406: dp->dp_secsiz = lp->d_secsize;
407: dp->dp_ptag = 0;
408: dp->dp_pflag = 0;
409: if (label) {
410: dp->dp_pstartsec = label->start;
411: dp->dp_pnumsec = label->size;
412: } else { /* added by Kevin */
413: dp->dp_pstartsec = -1;
414: dp->dp_pnumsec = -1;
415: }
416:
417: *count = sizeof(struct disk_parms) / sizeof(int);
418: break;
419: }
420: case V_RDABS:
421: if (*count < lp->d_secsize / sizeof(int)) {
422: printf("hd%d: RDABS, bad size %d\n", unit, *count);
423: return (EINVAL);
424: }
425: bp = geteblk(lp->d_secsize);
426: bp->b_flags = B_READ | B_ABS;
427: bp->b_blkno = sc->sc_abssn;
428: bp->b_dev = dev;
429: bp->b_bcount = lp->d_secsize;
430: hdstrategy(bp);
431: biowait(bp);
432: if (bp->b_flags & B_ERROR) {
433: printf("hd%d: RDABS failed\n", unit);
434: brelse(bp);
435: return (EIO);
436: }
437: bcopy(bp->b_un.b_addr, (caddr_t)data, lp->d_secsize);
438: brelse(bp);
439: *count = lp->d_secsize / sizeof(int);
440: break;
441:
442: case V_VERIFY:
443: {
444: int i, amt, n, error = 0;
445:
446: bp = geteblk(I386_PGBYTES);
447: bp->b_blkno = sc->sc_abssn;
448: bp->b_dev = dev;
449: amt = sc->sc_abscnt;
450: n = I386_PGBYTES / lp->d_secsize;
451: while (amt > 0) {
452: i = (amt > n) ? n : amt;
453: bp->b_bcount = i * lp->d_secsize;
454: bp->b_flags = B_READ | B_ABS;
455: hdstrategy(bp);
456: biowait(bp);
457: if (bp->b_flags & B_ERROR) {
458: error = BAD_BLK;
459: break;
460: }
461: amt -= bp->b_bcount;
462: bp->b_blkno += i;
463: }
464: brelse(bp);
465: data[0] = error;
466: *count = 1;
467: break;
468: }
469: default:
470: return (D_INVALID_OPERATION);
471: }
472: return (0);
473: }
474:
475: int
476: hdsetstat(dev, flavor, data, count)
477: dev_t dev;
478: dev_flavor_t flavor;
479: dev_status_t data;
480: mach_msg_type_number_t count;
481: {
482: int unit = hdunit(dev); /* , part = hdpart(dev); */
483: int error = 0 /*, s */;
484: struct hdsoftc *sc = &hdsoftc[unit];
485: struct disklabel *lp = &hdlabel[unit];
486: struct buf *bp;
487:
488: switch (flavor) {
489:
490: case DIOCWLABEL:
491: case DIOCWLABEL - (0x10 << 16):
492: break;
493:
494: case DIOCSDINFO:
495: case DIOCSDINFO - (0x10 << 16):
496: if (count != (sizeof(struct disklabel) / sizeof(int)))
497: return (D_INVALID_SIZE);
498: error = setdisklabel(lp, (struct disklabel *)data);
499: if (error == 0 && (sc->sc_flags & HDF_LBA) == 0)
500: sc->sc_flags |= HDF_SETPARAM;
501: break;
502:
503: case DIOCWDINFO:
504: case DIOCWDINFO - (0x10 << 16):
505: if (count != (sizeof(struct disklabel) / sizeof(int)))
506: return (D_INVALID_SIZE);
507: error = setdisklabel(lp, (struct disklabel *)data);
508: if (error == 0) {
509: if ((sc->sc_flags & HDF_LBA) == 0)
510: sc->sc_flags |= HDF_SETPARAM;
511: error = hdwritelabel(dev);
512: }
513: break;
514:
515: case V_REMOUNT:
516: hdinit(dev);
517: break;
518:
519: case V_ABS:
520: if (count != 1 && count != 2)
521: return (D_INVALID_OPERATION);
522: sc->sc_abssn = *(int *)data;
523: if (sc->sc_abssn < 0 || sc->sc_abssn >= lp->d_secperunit)
524: return (D_INVALID_OPERATION);
525: if (count == 2)
526: sc->sc_abscnt = *((int *)data + 1);
527: else
528: sc->sc_abscnt = 1;
529: if (sc->sc_abscnt <= 0
530: || sc->sc_abssn + sc->sc_abscnt > lp->d_secperunit)
531: return (D_INVALID_OPERATION);
532: break;
533:
534: case V_WRABS:
535: if (count < (lp->d_secsize / sizeof(int))) {
536: printf("hd%d: WRABS, bad size %d\n", unit, count);
537: return (D_INVALID_OPERATION);
538: }
539: bp = geteblk(lp->d_secsize);
540: bcopy((caddr_t)data, bp->b_un.b_addr, lp->d_secsize);
541: bp->b_flags = B_WRITE | B_ABS;
542: bp->b_blkno = sc->sc_abssn;
543: bp->b_bcount = lp->d_secsize;
544: bp->b_dev = dev;
545: hdstrategy(bp);
546: biowait(bp);
547: if (bp->b_flags & B_ERROR) {
548: printf("hd%d: WRABS failed\n", unit);
549: error = EIO;
550: }
551: brelse(bp);
552: break;
553:
554: default:
555: return (D_INVALID_OPERATION);
556: }
557: return (error);
558: }
559:
560: int
561: hddevinfo(dev, flavor, info)
562: dev_t dev;
563: int flavor;
564: char *info;
565: {
566: switch (flavor) {
567:
568: case D_INFO_BLOCK_SIZE:
569: *((int *)info) = SECSIZE; /* #defined to 512 */
570: break;
571:
572: default:
573: return (D_INVALID_OPERATION);
574: }
575: return (0);
576: }
577:
578:
579:
580:
581: /* Kevin T. Van Maren: Added this low-level routine for the unified
582: partition code. A pointer to this routine is passed, along with param* */
583: int
584: ide_read_fun(struct ide_driver_info *param, int sectornum, char *buff)
585: {
586: struct buf *bp;
587:
588: bp = geteblk(param->sectorsize);
589: bp->b_flags = B_READ | B_ABS;
590:
591: bp->b_bcount = param->sectorsize;
592: bp->b_blkno = sectornum;
593:
594: /* WARNING: DEPENDS ON NUMBER OF BITS FOR PARTITIONS */
595: bp->b_dev = param->dev & ~0x3ff;
596: hdstrategy(bp);
597: biowait(bp);
598: if ((bp->b_flags & B_ERROR) == 0)
599: bcopy((char *)bp->b_un.b_addr, buff, param->sectorsize);
600: else {
601: printf("ERROR!\n");
602: return(B_ERROR);
603: }
604:
605: brelse(bp);
606: return(0);
607: }
608:
609:
610:
611: /*
612: * Initialize drive.
613: */
614: int
615: hdinit(dev)
616: dev_t dev;
617: {
618: int unit = hdunit(dev);
619: struct hdsoftc *sc = &hdsoftc[unit];
620: struct disklabel *lp = &hdlabel[unit], *dlp;
621: struct buf *bp = 0;
622: int numpart;
623:
624: struct ide_driver_info ide_param = { dev, /* bp, */ lp->d_secsize };
625: int ret;
626:
627: /*
628: * Issue identify command.
629: */
630: if ((sc->sc_flags & HDF_IDENTDONE) == 0) {
631: sc->sc_flags |= HDF_IDENTDONE;
632: bp = geteblk(lp->d_secsize);
633: /* sector size #defined to 512 */
634: bp->b_flags = B_IDENTIFY;
635: bp->b_dev = dev;
636: hdstrategy(bp);
637: biowait(bp);
638: if ((bp->b_flags & B_ERROR) == 0) {
639: bcopy((char *)bp->b_un.b_addr,
640: (char *)&sc->sc_id, sizeof(struct hdident));
641:
642: /*
643: * Check if drive supports LBA mode.
644: */
645: if (sc->sc_id.id_capability & 2)
646: sc->sc_flags |= HDF_LBA;
647: }
648: }
649:
650: /*
651: * Check if drive supports multiple read/write mode.
652: */
653: hdmulti(dev);
654:
655: /* Note: label was fudged during attach! */
656:
657: /* ensure the 'raw disk' can be accessed reliably */
658: array[MAX_IDE_PARTS*unit].start=0;
659: array[MAX_IDE_PARTS*unit].size=lp->d_secperunit; /* fill in root for MY reads */
660: #if 0
661: array[MAX_IDE_PARTS*unit].subs=0;
662: array[MAX_IDE_PARTS*unit].nsubs=0;
663: array[MAX_IDE_PARTS*unit].type=0;
664: array[MAX_IDE_PARTS*unit].fsys=0;
665: #endif 0
666:
667: numpart=get_only_partition(&ide_param, (*ide_read_fun),
668: &array[MAX_IDE_PARTS*unit],MAX_IDE_PARTS,lp->d_secperunit,
669: drive_name[unit]);
670:
671: printf("%s %d partitions found\n",drive_name[unit],numpart);
672:
673: if ((sc->sc_flags & HDF_LBA) == 0)
674: sc->sc_flags |= HDF_SETPARAM;
675:
676: brelse(bp);
677: return(ret);
678: }
679:
680:
681:
682:
683: /*
684: * Check if drive supports multiple read/write mode.
685: */
686: int
687: hdmulti(dev)
688: dev_t dev;
689: {
690: int unit = hdunit(dev);
691: struct hdsoftc *sc = &hdsoftc[unit];
692: struct buf *bp;
693: struct hdident *id;
694:
695: if (sc->sc_flags & HDF_MULTIDONE)
696: return(0);
697:
698: sc->sc_flags |= HDF_MULTIDONE;
699:
700: if (hdenmulti == 0)
701: return(0);
702:
703: /*
704: * Get drive information by issuing IDENTIFY command.
705: */
706: bp = geteblk(DEV_BSIZE);
707: bp->b_flags = B_IDENTIFY;
708: bp->b_dev = dev;
709: hdstrategy(bp);
710: biowait(bp);
711: id = (struct hdident *)bp->b_un.b_addr;
712:
713: /*
714: * If controller does not recognise IDENTIFY command,
715: * or does not support multiple mode, clear count.
716: */
717: if ((bp->b_flags & B_ERROR) || !id->id_multisize)
718: sc->sc_multicnt = 0;
719: else {
720: sc->sc_multicnt = id->id_multisize;
721: printf("hd%d: max multiple size %u", unit, sc->sc_multicnt);
722: /*
723: * Use 4096 since it is the minimum block size in FFS.
724: */
725: if (sc->sc_multicnt > 4096 / 512)
726: sc->sc_multicnt = 4096 / 512;
727: printf(", using %u\n", sc->sc_multicnt);
728: sc->sc_flags |= HDF_SETMULTI;
729: }
730: brelse(bp);
731: }
732:
733: /*
734: * Write label to disk.
735: */
736: int
737: hdwritelabel(dev)
738: dev_t dev;
739: {
740: int unit = hdunit(dev), error = 0;
741: long labelsect;
742: struct buf *bp;
743: struct disklabel *lp = &hdlabel[unit];
744:
745: printf("hdwritelabel: no longer implemented\n");
746:
747: #if 0
748: bp = geteblk(lp->d_secsize);
749: bp->b_flags = B_READ | B_ABS;
750: bp->b_blkno = LBLLOC + lp->d_partitions[PART_DISK].p_offset;
751: bp->b_bcount = lp->d_secsize;
752: bp->b_dev = dev;
753: hdstrategy(bp);
754: biowait(bp);
755: if (bp->b_flags & B_ERROR) {
756: printf("hd%d: hdwritelabel(), error reading disklabel\n",unit);
757: error = EIO;
758: goto out;
759: }
760: *(struct disklabel *)bp->b_un.b_addr = *lp; /* copy disk label */
761: bp->b_flags = B_WRITE | B_ABS;
762: hdstrategy(bp);
763: biowait(bp);
764: if (bp->b_flags & B_ERROR) {
765: printf("hd%d: hdwritelabel(), error writing disklabel\n",unit);
766: error = EIO;
767: }
768: out:
769: brelse(bp);
770: #endif 0
771:
772: return (error);
773: }
774:
775: /*
776: * Strategy routine.
777: * Enqueue request on drive.
778: */
779: int
780: hdstrategy(bp)
781: struct buf *bp;
782: {
783: int unit = hdunit(bp->b_dev), part = hdpart(bp->b_dev), s;
784: long bn, sz, maxsz;
785: struct buf *dp;
786: struct hdsoftc *sc = &hdsoftc[unit];
787: struct bus_device *ui = hddinfo[unit];
788: struct disklabel *lp = &hdlabel[unit];
789: struct diskpart *label;
790:
791: if (bp->b_flags & B_IDENTIFY) {
792: bp->b_cylin = 0;
793: goto q;
794: }
795: bn = bp->b_blkno;
796: if (bp->b_flags & B_ABS)
797: goto q1;
798: sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
799: label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(bp->b_dev));
800: if (label) {
801: maxsz = label->size;
802: } else {
803: bp->b_flags |= B_ERROR;
804: bp->b_error = EINVAL;
805: goto done;
806: }
807:
808: if (bn < 0 || bn + sz > maxsz) {
809: if (bn == maxsz) {
810: bp->b_resid = bp->b_bcount;
811: goto done;
812: }
813: sz = maxsz - bn;
814: if (sz <= 0) {
815: bp->b_flags |= B_ERROR;
816: bp->b_error = EINVAL;
817: goto done;
818: }
819: bp->b_bcount = sz * lp->d_secsize;
820: }
821: bn += lp->d_partitions[part].p_offset;
822: bn += label->start;
823:
824: q1:
825: bp->b_cylin = (sc->sc_flags & HDF_LBA) ? bn : bn / lp->d_secpercyl;
826: q:
827: dp = &hdutab[unit];
828: s = splbio();
829: disksort(dp, bp);
830: if (!dp->b_active) {
831: hdustart(ui);
832: if (!hdtab[ui->mi->unit].b_active)
833: hdstart(ui->mi);
834: }
835: splx(s);
836: return(0);
837: done:
838: biodone(bp);
839: return(0);
840: }
841:
842: /*
843: * Unit start routine.
844: * Move request from drive to controller queue.
845: */
846: int
847: hdustart(ui)
848: struct bus_device *ui;
849: {
850: struct buf *bp;
851: struct buf *dp;
852:
853: bp = &hdutab[ui->unit];
854: if (bp->b_actf == 0)
855: return(0);
856: dp = &hdtab[ui->mi->unit];
857: if (dp->b_actf == 0)
858: dp->b_actf = bp;
859: else
860: dp->b_actl->b_forw = bp;
861: bp->b_forw = 0;
862: dp->b_actl = bp;
863: bp->b_active++;
864: }
865:
866: /*
867: * Start output on controller.
868: */
869: int
870: hdstart(um)
871: struct bus_ctlr *um;
872: {
873: long bn;
874: struct buf *bp;
875: struct buf *dp;
876: struct hdsoftc *sc;
877: struct hdcsoftc *hdc;
878: struct bus_device *ui;
879: struct disklabel *lp;
880: struct diskpart *label;
881:
882: /*
883: * Pull a request from the controller queue.
884: */
885: dp = &hdtab[um->unit];
886: if ((bp = dp->b_actf) == 0)
887: return(0);
888: bp = bp->b_actf;
889:
890: hdc = &hdcsoftc[um->unit];
891: ui = hddinfo[hdunit(bp->b_dev)];
892: sc = &hdsoftc[ui->unit];
893: lp = &hdlabel[ui->unit];
894:
895: label = lookup_part(&array[MAX_IDE_PARTS*hdunit(bp->b_dev)], hdpart(bp->b_dev));
896:
897: /*
898: * Mark controller busy.
899: */
900: dp->b_active++;
901:
902: if (bp->b_flags & B_IDENTIFY) {
903: hdc->sc_state = IDENTIFY;
904: goto doit;
905: }
906:
907: /*
908: * Figure out where this request is going.
909: */
910: if (sc->sc_flags & HDF_LBA)
911: hdc->sc_cn = bp->b_cylin;
912: else {
913: bn = bp->b_blkno;
914: if ((bp->b_flags & B_ABS) == 0) {
915: bn += label->start; /* partition must be valid */
916: }
917: hdc->sc_cn = bp->b_cylin;
918: hdc->sc_sn = bn % lp->d_secpercyl;
919: hdc->sc_tn = hdc->sc_sn / lp->d_nsectors;
920: hdc->sc_sn %= lp->d_nsectors;
921: }
922:
923: /*
924: * Set up for multi-sector transfer.
925: */
926: hdc->sc_addr = bp->b_un.b_addr;
927: hdc->sc_resid = bp->b_bcount;
928: hdc->sc_wticks = 0;
929: hdc->sc_recalerr = 0;
930: hdc->sc_ioerr = 0;
931:
932: /*
933: * Set initial transfer state.
934: */
935: if (sc->sc_flags & HDF_SETPARAM)
936: hdc->sc_state = SETPARAM;
937: else if (sc->sc_flags & HDF_RESTORE)
938: hdc->sc_state = RESTORE;
939: else if (sc->sc_flags & HDF_SETMULTI)
940: hdc->sc_state = SETMULTI;
941: else
942: hdc->sc_state = TRANSFER;
943:
944: doit:
945: /*
946: * Call transfer state routine to do the actual I/O.
947: */
948: hdstate(um);
949: }
950:
951: /*
952: * Interrupt routine.
953: */
954: int
955: hdintr(ctlr)
956: int ctlr;
957: {
958: int timedout;
959: struct bus_ctlr *um = hdminfo[ctlr];
960: struct bus_device *ui;
961: struct buf *bp;
962: struct buf *dp = &hdtab[ctlr];
963: struct hdcsoftc *hdc = &hdcsoftc[ctlr];
964:
965: if (!dp->b_active) {
966: (void) inb(HD_STATUS(um->address));
967: printf("hdc%d: stray interrupt\n", ctlr);
968: return(0);
969: }
970: timedout = hdc->sc_wticks >= OP_TIMEOUT;
971: hdc->sc_wticks = 0;
972:
973: /*
974: * Operation timed out, terminate request.
975: */
976: if (timedout) {
977: bp = dp->b_actf->b_actf;
978: ui = hddinfo[hdunit(bp->b_dev)];
979: hderror("timed out", ui);
980: hdsoftc[ui->unit].sc_flags |= HDF_RESTORE;
981: bp->b_flags |= B_ERROR;
982: bp->b_error = EIO;
983: hddone(ui, bp);
984: return(0);
985: }
986:
987: /*
988: * Let transfer state routine handle the rest.
989: */
990: hdstate(um);
991: }
992:
993: /*
994: * Transfer finite state machine driver.
995: */
996: int
997: hdstate(um)
998: struct bus_ctlr *um;
999: {
1000: char *msg;
1001: int op;
1002: struct buf *bp;
1003: struct hdsoftc *sc;
1004: struct bus_device *ui;
1005: struct disklabel *lp;
1006: struct hdcsoftc *hdc = &hdcsoftc[um->unit];
1007: struct hdbios *bg;
1008:
1009: bp = hdtab[um->unit].b_actf->b_actf;
1010: ui = hddinfo[hdunit(bp->b_dev)];
1011: lp = &hdlabel[ui->unit];
1012: sc = &hdsoftc[ui->unit];
1013: bg = &hdbios[ui->unit];
1014:
1015: /*
1016: * Ensure controller is not busy.
1017: */
1018: if (!hdwait(um))
1019: goto ctlr_err;
1020:
1021: while (1) switch (hdc->sc_state) {
1022:
1023: case SETPARAM:
1024: /*
1025: * Set drive parameters.
1026: */
1027: outb(HD_DRVHD(um->address),
1028: 0xa0 | (ui->slave << 4) | (lp->d_ntracks - 1));
1029: outb(HD_SECTCNT(um->address), lp->d_nsectors);
1030: outb(HD_CMD(um->address), CMD_SETPARAM);
1031: hdc->sc_state = SETPARAMDONE;
1032: return(0);
1033:
1034: case SETPARAMDONE:
1035: /*
1036: * Set parameters complete.
1037: */
1038: if (msg = hderrchk(um))
1039: goto bad;
1040: sc->sc_flags &= ~HDF_SETPARAM;
1041: hdc->sc_state = RESTORE;
1042: break;
1043:
1044: case RESTORE:
1045: /*
1046: * Recalibrate drive.
1047: */
1048: outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4));
1049: outb(HD_CMD(um->address), CMD_RESTORE);
1050: hdc->sc_state = RESTOREDONE;
1051: return(0);
1052:
1053: case RESTOREDONE:
1054: /*
1055: * Recalibration complete.
1056: */
1057: if (msg = hderrchk(um)) {
1058: if (++hdc->sc_recalerr == 2)
1059: goto bad;
1060: hdc->sc_state = RESTORE;
1061: break;
1062: }
1063: sc->sc_flags &= ~HDF_RESTORE;
1064: hdc->sc_recalerr = 0;
1065: if (sc->sc_flags & HDF_SETMULTI)
1066: hdc->sc_state = SETMULTI;
1067: else
1068: hdc->sc_state = TRANSFER;
1069: break;
1070:
1071: case TRANSFER:
1072: /*
1073: * Perform I/O transfer.
1074: */
1075: sc->sc_flags &= ~HDF_UNALIGNED;
1076: hdc->sc_state = TRANSFERDONE;
1077: hdc->sc_amt = hdc->sc_resid / lp->d_secsize;
1078: if (hdc->sc_amt == 0) {
1079: sc->sc_flags |= HDF_UNALIGNED;
1080: hdc->sc_amt = 1;
1081: } else if (hdc->sc_amt > 256)
1082: hdc->sc_amt = 256;
1083: if (sc->sc_multicnt > 1 && hdc->sc_amt >= sc->sc_multicnt) {
1084: hdc->sc_cnt = sc->sc_multicnt;
1085: hdc->sc_amt -= hdc->sc_amt % hdc->sc_cnt;
1086: if (bp->b_flags & B_READ)
1087: op = CMD_READMULTI;
1088: else
1089: op = CMD_WRITEMULTI;
1090: } else {
1091: hdc->sc_cnt = 1;
1092: if (bp->b_flags & B_READ)
1093: op = CMD_READ;
1094: else
1095: op = CMD_WRITE;
1096: }
1097: if (sc->sc_flags & HDF_LBA) {
1098: outb(HD_DRVHD(um->address),
1099: (0xe0 | (ui->slave << 4)
1100: | ((hdc->sc_cn >> 24) & 0x0f)));
1101: outb(HD_SECT(um->address), hdc->sc_cn);
1102: outb(HD_CYLLO(um->address), hdc->sc_cn >> 8);
1103: outb(HD_CYLHI(um->address), hdc->sc_cn >> 16);
1104: } else {
1105: outb(HD_DRVHD(um->address),
1106: 0xa0 | (ui->slave << 4) | hdc->sc_tn);
1107: outb(HD_SECT(um->address), hdc->sc_sn + 1);
1108: outb(HD_CYLLO(um->address), hdc->sc_cn);
1109: outb(HD_CYLHI(um->address), hdc->sc_cn >> 8);
1110: }
1111: outb(HD_SECTCNT(um->address), hdc->sc_amt & 0xff);
1112: outb(HD_PRECOMP(um->address), bg->bg_precomp / 4);
1113: outb(HD_CMD(um->address), op);
1114: if ((bp->b_flags & B_READ) == 0) {
1115: int i;
1116: caddr_t buf;
1117:
1118: if (sc->sc_flags & HDF_UNALIGNED) {
1119: buf = hdc->sc_buf;
1120: bcopy(hdc->sc_addr, buf, hdc->sc_resid);
1121: bzero(buf + hdc->sc_resid,
1122: lp->d_secsize - hdc->sc_resid);
1123: } else
1124: buf = hdc->sc_addr;
1125: for (i = 0; i < 1000000; i++)
1126: if (inb(HD_STATUS(um->address)) & ST_DREQ) {
1127: loutw(HD_DATA(um->address), buf,
1128: hdc->sc_cnt * lp->d_secsize / 2);
1129: return(0);
1130: }
1131: goto ctlr_err;
1132: }
1133: return(0);
1134:
1135: case TRANSFERDONE:
1136: /*
1137: * Transfer complete.
1138: */
1139: if (msg = hderrchk(um)) {
1140: if (++hdc->sc_ioerr == MAX_RETRIES)
1141: goto bad;
1142: /*
1143: * Every fourth attempt print a message
1144: * and recalibrate the drive.
1145: */
1146: if (hdc->sc_ioerr & 3)
1147: hdc->sc_state = TRANSFER;
1148: else {
1149: hderror(msg, ui);
1150: hdc->sc_state = RESTORE;
1151: }
1152: break;
1153: }
1154: if (bp->b_flags & B_READ) {
1155: if (sc->sc_flags & HDF_UNALIGNED) {
1156: linw(HD_DATA(um->address), hdc->sc_buf,
1157: lp->d_secsize / 2);
1158: bcopy(hdc->sc_buf, hdc->sc_addr,
1159: hdc->sc_resid);
1160: } else
1161: linw(HD_DATA(um->address), hdc->sc_addr,
1162: hdc->sc_cnt * lp->d_secsize / 2);
1163: }
1164: hdc->sc_resid -= hdc->sc_cnt * lp->d_secsize;
1165: if (hdc->sc_resid <= 0) {
1166: bp->b_resid = 0;
1167: hddone(ui, bp);
1168: return(0);
1169: }
1170: if (sc->sc_flags & HDF_LBA)
1171: hdc->sc_cn += hdc->sc_cnt;
1172: else {
1173: hdc->sc_sn += hdc->sc_cnt;
1174: while (hdc->sc_sn >= lp->d_nsectors) {
1175: hdc->sc_sn -= lp->d_nsectors;
1176: if (++hdc->sc_tn == lp->d_ntracks) {
1177: hdc->sc_tn = 0;
1178: hdc->sc_cn++;
1179: }
1180: }
1181: }
1182: hdc->sc_ioerr = 0;
1183: hdc->sc_addr += hdc->sc_cnt * lp->d_secsize;
1184: hdc->sc_amt -= hdc->sc_cnt;
1185: if (hdc->sc_amt == 0) {
1186: hdc->sc_state = TRANSFER;
1187: break;
1188: }
1189: if ((bp->b_flags & B_READ) == 0) {
1190: int i;
1191:
1192: for (i = 0; i < 1000000; i++)
1193: if (inb(HD_STATUS(um->address)) & ST_DREQ) {
1194: loutw(HD_DATA(um->address),
1195: hdc->sc_addr,
1196: hdc->sc_cnt * lp->d_secsize / 2);
1197: return(0);
1198: }
1199: goto ctlr_err;
1200: }
1201: return(0);
1202:
1203: case IDENTIFY:
1204: /*
1205: * Get drive info.
1206: */
1207: hdc->sc_state = IDENTIFYDONE;
1208: outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4));
1209: outb(HD_CMD(um->address), CMD_IDENTIFY);
1210: return(0);
1211:
1212: case IDENTIFYDONE:
1213: /*
1214: * Get drive info complete.
1215: */
1216: if (msg = hderrchk(um))
1217: goto bad;
1218: linw(HD_DATA(um->address), (u_short *)bp->b_un.b_addr, 256);
1219: hddone(ui, bp);
1220: return(0);
1221:
1222: case SETMULTI:
1223: /*
1224: * Set multiple mode count.
1225: */
1226: hdc->sc_state = SETMULTIDONE;
1227: outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4));
1228: outb(HD_SECTCNT(um->address), sc->sc_multicnt);
1229: outb(HD_CMD(um->address), CMD_SETMULTI);
1230: return(0);
1231:
1232: case SETMULTIDONE:
1233: /*
1234: * Set multiple mode count complete.
1235: */
1236: sc->sc_flags &= ~HDF_SETMULTI;
1237: if (msg = hderrchk(um)) {
1238: sc->sc_multicnt = 0;
1239: goto bad;
1240: }
1241: hdc->sc_state = TRANSFER;
1242: break;
1243:
1244: default:
1245: printf("hd%d: invalid state\n", ui->unit);
1246: panic("hdstate");
1247: /*NOTREACHED*/
1248: }
1249:
1250: ctlr_err:
1251: msg = "controller error";
1252:
1253: bad:
1254: hderror(msg, ui);
1255: bp->b_flags |= B_ERROR;
1256: bp->b_error = EIO;
1257: sc->sc_flags |= HDF_RESTORE;
1258: hddone(ui, bp);
1259: }
1260:
1261: /*
1262: * Terminate current request and start
1263: * any others that are queued.
1264: */
1265: int
1266: hddone(ui, bp)
1267: struct bus_device *ui;
1268: struct buf *bp;
1269: {
1270: struct bus_ctlr *um = ui->mi;
1271: struct hdsoftc *sc = &hdsoftc[ui->unit];
1272: struct hdcsoftc *hdc = &hdcsoftc[um->unit];
1273: struct buf *dp = &hdtab[um->unit];
1274:
1275: sc->sc_flags &= ~HDF_UNALIGNED;
1276:
1277: /*
1278: * Remove this request from queue.
1279: */
1280: hdutab[ui->unit].b_actf = bp->b_actf;
1281: biodone(bp);
1282: bp = &hdutab[ui->unit];
1283: dp->b_actf = bp->b_forw;
1284:
1285: /*
1286: * Mark controller and drive idle.
1287: */
1288: dp->b_active = 0;
1289: bp->b_active = 0;
1290: hdc->sc_state = IDLE;
1291:
1292: /*
1293: * Start up other requests.
1294: */
1295: hdustart(ui);
1296: hdstart(um);
1297:
1298: /*
1299: * Wakeup anyone waiting for drive.
1300: */
1301: if (sc->sc_flags & HDF_WANT) {
1302: sc->sc_flags &= ~HDF_WANT;
1303: wakeup((caddr_t)sc);
1304: }
1305: }
1306:
1307: /*
1308: * Wait for controller to be idle.
1309: */
1310: int
1311: hdwait(um)
1312: struct bus_ctlr *um;
1313: {
1314: int i, status;
1315:
1316: for (i = 0; i < 1000000; i++) {
1317: status = inb(HD_STATUS(um->address));
1318: if ((status & ST_BUSY) == 0 && (status & ST_READY))
1319: return (status);
1320: }
1321: return (0);
1322: }
1323:
1324: /*
1325: * Check for errors on completion of an operation.
1326: */
1327: char *
1328: hderrchk(um)
1329: struct bus_ctlr *um;
1330: {
1331: int status;
1332:
1333: status = inb(HD_STATUS(um->address));
1334: if (status & ST_WRTFLT)
1335: return ("write fault");
1336: if (status & ST_ERROR) {
1337: status = inb(HD_ERROR(um->address));
1338: if (status & ERR_DAM)
1339: return ("data address mark not found");
1340: if (status & ERR_TR0)
1341: return ("track 0 not found");
1342: if (status & ERR_ID)
1343: return ("sector not found");
1344: if (status & ERR_ECC)
1345: return ("uncorrectable ECC error");
1346: if (status & ERR_BADBLK)
1347: return ("bad block detected");
1348: if (status & ERR_ABORT)
1349: return ("command aborted");
1350: return ("hard error");
1351: }
1352: return (NULL);
1353: }
1354:
1355: /*
1356: * Print an error message.
1357: */
1358: hderror(msg, ui)
1359: char *msg;
1360: struct bus_device *ui;
1361: {
1362: char *op;
1363: int prn_sn = 0;
1364: struct hdcsoftc *hdc = &hdcsoftc[ui->mi->unit];
1365:
1366: switch (hdc->sc_state) {
1367:
1368: case SETPARAM:
1369: case SETPARAMDONE:
1370: op = "SETPARAM: ";
1371: break;
1372:
1373: case RESTORE:
1374: case RESTOREDONE:
1375: op = "RESTORE: ";
1376: break;
1377:
1378: case TRANSFER:
1379: case TRANSFERDONE:
1380: if (hdutab[ui->unit].b_actf->b_flags & B_READ)
1381: op = "READ: ";
1382: else
1383: op = "WRITE: ";
1384: prn_sn = 1;
1385: break;
1386:
1387: case IDENTIFY:
1388: case IDENTIFYDONE:
1389: op = "IDENTIFY: ";
1390: break;
1391:
1392: case SETMULTI:
1393: case SETMULTIDONE:
1394: op = "SETMULTI: ";
1395: break;
1396:
1397: default:
1398: op = "";
1399: break;
1400: }
1401: printf("hd%d: %s%s", ui->unit, op, msg);
1402: if (prn_sn) {
1403: if (hdsoftc[ui->unit].sc_flags & HDF_LBA)
1404: printf(", bn %d", hdc->sc_cn);
1405: else
1406: printf(", cn %d tn %d sn %d",
1407: hdc->sc_cn, hdc->sc_tn, hdc->sc_sn + 1);
1408: }
1409: printf("\n");
1410: }
1411:
1412: /*
1413: * Watchdog routine.
1414: * Check for any hung operations.
1415: */
1416: void
1417: hdwatch()
1418: {
1419: int unit, s;
1420:
1421: timeout(hdwatch, 0, hz);
1422: s = splbio();
1423: for (unit = 0; unit < NHDC; unit++)
1424: if (hdtab[unit].b_active
1425: && ++hdcsoftc[unit].sc_wticks >= OP_TIMEOUT)
1426: hdintr(unit);
1427: splx(s);
1428: }
1429:
1430: #endif /* NHD > 0 && !LINUX_DEV */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.