FreeBSD/Linux Kernel Cross Reference
sys/i386at/hd.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: hd.c,v $
29 * Revision 2.23 93/08/10 15:57:25 mrt
30 * We now use bsd labels internally and convert from "local labels"
31 * if we find them on the disk.
32 * [93/08/03 20:36:05 rvb]
33 *
34 * Fix DIOCxxx ioctls to deal with MAXPARTITION or MAXPARTITION+1
35 * parititions. We'll do this better next release.
36 *
37 * Revision 2.22 93/05/10 20:03:39 rvb
38 * Types.
39 * [93/05/08 11:17:48 af]
40 *
41 * Revision 2.21 93/03/11 13:58:01 danner
42 * u_long -> u_int.
43 * [93/03/09 danner]
44 *
45 * Revision 2.20 93/01/24 13:15:53 danner
46 * Deal with DPT WD1003 emulation that clears BUSY before READY is
47 * set.
48 * [92/10/01 rvb]
49 *
50 * Revision 2.19 93/01/14 17:30:21 danner
51 * Proper spl typing.
52 * [92/11/30 af]
53 *
54 * Revision 2.18 92/07/09 22:54:06 rvb
55 * Transcription error missed a line.
56 * [92/06/23 11:16:20 rvb]
57 *
58 * Setcontroller should be called synchronously with hd_start(). So
59 * that the controller is idle.
60 * [92/06/20 rvb]
61 *
62 * Defer setcontroller(unit) to getvtoc(); So we only setcontroller()
63 * what we open, not what we probe. ESDI+SCSI messes up the device
64 * count.
65 * [92/06/18 rvb]
66 *
67 * Revision 2.17 92/03/01 00:39:53 rpd
68 * Cleaned up syntactically incorrect ifdefs.
69 * [92/02/29 rpd]
70 *
71 * Revision 2.16 92/02/23 22:43:07 elf
72 * Added (mandatory) DEV_GET_SIZE flavor of get_status.
73 * [92/02/22 af]
74 *
75 * Revision 2.15 92/02/19 16:29:51 elf
76 * On 25-Jan, did not consider NO ACTIVE mach parition.
77 * Add "BIOS" support -- always boot mach partition NOT active one.
78 * [92/01/31 rvb]
79 *
80 * Revision 2.14 92/01/27 16:43:06 rpd
81 * Fixed hdgetstat and hdsetstat to return D_INVALID_OPERATION
82 * for unsupported flavors.
83 * [92/01/26 rpd]
84 *
85 * Revision 2.13 92/01/14 16:43:51 rpd
86 * Error in badblock_mapping code in the case there was sector replacement.
87 * For all the sectors in the disk block before the bad sector, you
88 * badblock_mapping should give the identity map and it was not.
89 * [92/01/08 rvb]
90 *
91 * Revision 2.12 91/11/18 17:34:19 rvb
92 * For now, back out the hdprobe(), hdslave() probes and use
93 * the old simple test and believe BIOS.
94 *
95 * Revision 2.11 91/11/12 11:09:32 rvb
96 * Amazing how hard getting the probe to work for all machines is.
97 * V_REMOUNT must clear gotvtoc[].
98 * [91/10/16 rvb]
99 *
100 * Revision 2.10 91/10/07 17:25:35 af
101 * Now works with 2 disk drives, new probe/slave routines, misc cleanup
102 * [91/08/07 mg32]
103 *
104 * From 2.5:
105 * Rationalize p_flag
106 * Kill nuisance print out.
107 * Removed "hdioctl(): do not recognize ioctl ..." printf().
108 * [91/08/07 rvb]
109 *
110 * Revision 2.9 91/08/28 11:11:42 jsb
111 * Replace hdbsize with hddevinfo.
112 * [91/08/12 17:33:59 dlb]
113 *
114 * Add block size routine.
115 * [91/08/05 17:39:16 dlb]
116 *
117 * Revision 2.8 91/08/24 11:57:46 af
118 * New MI autoconf.
119 * [91/08/02 02:52:47 af]
120 *
121 * Revision 2.7 91/05/14 16:23:24 mrt
122 * Correcting copyright
123 *
124 * Revision 2.6 91/02/05 17:17:01 mrt
125 * Changed to new Mach copyright
126 * [91/02/01 17:43:01 mrt]
127 *
128 * Revision 2.5 91/01/08 17:32:51 rpd
129 * Allow ioctl's
130 * [90/12/19 rvb]
131 *
132 * Revision 2.4 90/11/26 14:49:37 rvb
133 * jsb bet me to XMK34, sigh ...
134 * [90/11/26 rvb]
135 * Synched 2.5 & 3.0 at I386q (r1.8.1.15) & XMK35 (r2.4)
136 * [90/11/15 rvb]
137 *
138 * Revision 1.8.1.14 90/09/18 08:38:49 rvb
139 * Typo & vs && at line 592. [contrib]
140 * Make Status printout on error only conditional on hd_print_error.
141 * So we can get printout during clobber_my_disk.
142 * [90/09/08 rvb]
143 *
144 * Revision 1.8.1.13 90/08/25 15:44:38 rvb
145 * Use take_<>_irq() vs direct manipulations of ivect and friends.
146 * [90/08/20 rvb]
147 *
148 * Revision 1.8.1.12 90/07/27 11:25:30 rvb
149 * Fix Intel Copyright as per B. Davies authorization.
150 * Let anyone who as opened the disk do absolute io.
151 * [90/07/27 rvb]
152 *
153 * Revision 1.8.1.11 90/07/10 11:43:22 rvb
154 * Unbelievable bug in setcontroller.
155 * New style probe/slave/attach.
156 * [90/06/15 rvb]
157 *
158 * Revision 1.8.1.10 90/03/29 19:00:00 rvb
159 * Conditionally, print out state info for "state error".
160 * [90/03/26 rvb]
161 *
162 * Revision 1.8.1.8 90/03/10 00:27:20 rvb
163 * Fence post error iff (bp->b_blkno + hh.blocktotal ) > partition_p->p_size)
164 * [90/03/10 rvb]
165 *
166 * Revision 1.8.1.7 90/02/28 15:49:35 rvb
167 * Fix numerous typo's in Olivetti disclaimer.
168 * [90/02/28 rvb]
169 *
170 * Revision 1.8.1.6 90/01/16 15:54:14 rvb
171 * FLush pdinfo/vtoc -> evtoc
172 * [90/01/16 rvb]
173 *
174 * Must be able to return "dos{cyl,head,sector}"
175 * [90/01/12 rvb]
176 *
177 * Be careful about p_size bound's checks if B_MD1 is true.
178 * [90/01/12 rvb]
179 *
180 * Revision 1.8.1.5 90/01/08 13:29:29 rvb
181 * Add Intel copyright.
182 * Add Olivetti copyright.
183 * [90/01/08 rvb]
184 *
185 * It is no longer possible to set the start and size of disk
186 * partition "PART_DISK" -- it is always loaded from the DOS
187 * partition data.
188 * [90/01/08 rvb]
189 *
190 * Revision 1.8.1.4 90/01/02 13:54:58 rvb
191 * Temporarily regress driver to one that is known to work with Vectra's.
192 *
193 */
194
195
196 /*
197 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
198
199 All Rights Reserved
200
201 Permission to use, copy, modify, and distribute this software and
202 its documentation for any purpose and without fee is hereby
203 granted, provided that the above copyright notice appears in all
204 copies and that both the copyright notice and this permission notice
205 appear in supporting documentation, and that the name of Intel
206 not be used in advertising or publicity pertaining to distribution
207 of the software without specific, written prior permission.
208
209 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
210 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
211 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
212 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
213 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
214 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
215 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
216 */
217
218 /*
219 * AT Hard Disk Driver
220 * Copyright Ing. C. Olivetti & S.p.A. 1989
221 * All rights reserved.
222 *
223 */
224 /*
225 Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
226 Cupertino, California.
227
228 All Rights Reserved
229
230 Permission to use, copy, modify, and distribute this software and
231 its documentation for any purpose and without fee is hereby
232 granted, provided that the above copyright notice appears in all
233 copies and that both the copyright notice and this permission notice
234 appear in supporting documentation, and that the name of Olivetti
235 not be used in advertising or publicity pertaining to distribution
236 of the software without specific, written prior permission.
237
238 OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
239 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
240 IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
241 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
242 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
243 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
244 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
245 */
246
247 #include <hd.h>
248
249 #include <sys/types.h>
250 #ifdef MACH_KERNEL
251 #define PRIBIO 20
252 #include <device/buf.h>
253 #include <device/errno.h>
254 #include <device/device_types.h>
255 #include <device/disk_status.h>
256 #else MACH_KERNEL
257 #include <sys/buf.h>
258 #include <sys/user.h>
259 #endif MACH_KERNEL
260 #include <sys/ioctl.h>
261 #include <i386/pio.h>
262 #include <i386/ipl.h>
263 #include <i386at/disk.h>
264 #include <chips/busses.h>
265 #include <i386at/hdreg.h>
266
267 #define LABEL_DEBUG(x,y) if (label_flag&x) y
268
269 /* From sys/systm.h */
270 struct buf *geteblk();
271
272 #define b_cylin b_resid
273 #define PAGESIZ 4096
274
275 int devaddr[NHD/2];
276 int hdalive[NHD];
277 int hdgotvtoc[NHD];
278 struct hh hh[NHD/2];
279 struct alt_info alt_info[NHD];
280 struct buf hdbuf[NHD], hdunit[NHD];
281
282 int need_set_controller[NHD/2];
283
284 struct disklabel label[NHD];
285 int labeloffset[NHD];
286 int labelsector[NHD];
287
288 struct hd_param {
289 unsigned short ncyl;
290 unsigned short nheads;
291 unsigned short precomp;
292 unsigned short nsec;
293 } dosparm[NHD];
294
295 int hdstrategy(), hdminphys(), hdprobe(), hdslave(), hdintr();
296 void hdattach();
297 struct bus_device *hdinfo[NHD];
298
299 vm_offset_t hd_std[NHD] = { 0 };
300 struct bus_device *hd_dinfo[NHD*NDRIVES];
301 struct bus_ctlr *hd_minfo[NHD];
302 struct bus_driver hddriver = {
303 hdprobe, hdslave, hdattach, 0, hd_std, "hd", hd_dinfo, "hdc", hd_minfo, 0};
304
305
306 hdprobe(port, ctlr)
307 struct bus_ctlr *ctlr;
308 {
309 int i,
310 ctrl = ctlr->unit;
311 int addr = devaddr[ctrl] = (int)ctlr->address;
312
313 outb(PORT_DRIVE_HEADREGISTER(addr),0);
314 outb(PORT_COMMAND(addr),CMD_RESTORE);
315 for (i=500000; i && inb(PORT_STATUS(addr))&STAT_BUSY; i--);
316 for (; i; i--) {
317 if (inb(PORT_STATUS(addr))&STAT_READY) {
318 take_ctlr_irq(ctlr);
319 hh[ctrl].curdrive = ctrl<<1;
320 printf("%s%d: port = %x, spl = %d, pic = %d.\n", ctlr->name,
321 ctlr->unit, ctlr->address, ctlr->sysdep, ctlr->sysdep1);
322 #if 0
323 /* may be necesary for two controllers */
324 outb(FIXED_DISK_REG(ctrl), 4);
325 for(i = 0; i < 10000; i++);
326 outb(FIXED_DISK_REG(ctrl), 0);
327 #endif
328 return(1);
329 }
330 }
331 return(0);
332 }
333
334 /*
335 * hdslave:
336 *
337 * Actually should be thought of as a slave probe.
338 *
339 */
340
341 hdslave(dev, xxx)
342 struct bus_device *dev;
343 {
344 int i, j,
345 addr = devaddr[dev->ctlr];
346 u_char *bios_magic = (u_char *)(0xc0000475);
347
348 if (dev->ctlr == 0) /* for now: believe DOS */
349 if (*bios_magic >= 1 + dev->slave)
350 return 1;
351 else
352 return 0;
353 else
354 return 1;
355
356 #if 0
357 /* it is working on all types of PCs */
358 outb(PORT_DRIVE_HEADREGISTER(addr),dev->slave<<4);
359 outb(PORT_COMMAND(addr),CMD_RESTORE);
360
361 for (i=350000; i && (j = inb(PORT_STATUS(addr)))&STAT_BUSY; i--);
362 for (j = 0; i && !(j & STAT_READY); i--)
363 j = inb(PORT_STATUS(addr));
364 if (i == 0) {
365 outb(FIXED_DISK_REG(dev->ctlr), 4);
366 for(i = 0; i < 10000; i++);
367 outb(FIXED_DISK_REG(dev->ctlr), 0);
368 setcontroller(dev->slave);
369 return 0;
370 }
371 return(j&STAT_READY);
372 #endif
373 }
374
375 /*
376 * hdattach:
377 *
378 * Attach the drive unit that has been successfully probed. For the
379 * AT ESDI drives we will initialize all driver specific structures
380 * and complete the controller attach of the drive.
381 *
382 */
383
384 void hdattach(dev)
385 struct bus_device *dev;
386 {
387 int unit = dev->unit;
388 struct disklabel *lp = &label[unit];
389 u_int n;
390 u_char *tbl;
391
392 hdalive[unit] = 1;
393 n = *(unsigned long *)phystokv(dev->address);
394 tbl = (unsigned char *)phystokv((n&0xffff) + ((n>>12)&0xffff0));
395 dosparm[unit].ncyl = *(unsigned short *)tbl;
396 dosparm[unit].nheads = *(unsigned char *)(tbl+2);
397 dosparm[unit].precomp = *(unsigned short *)(tbl+5);
398 dosparm[unit].nsec = *(unsigned char *)(tbl+14);
399 printf(", stat = %x, spl = %d, pic = %d\n",
400 dev->address, dev->sysdep, dev->sysdep1);
401
402 /*
403 * copy initial parameters into label
404 */
405 fudge_bsd_label(lp, DTYPE_ESDI, dosparm[unit].ncyl, dosparm[unit].nheads,
406 dosparm[unit].nsec, 2);
407
408 if (unit<2)
409 printf(" hd%d: %dMeg, cyls %d, heads %d, secs %d, precomp %d",
410 unit, lp->d_secperunit * 512/1000000,
411 lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors,
412 dosparm[unit].precomp);
413 else
414 printf("hd%d: Capacity not available through bios\n",unit);
415 }
416
417 hdopen(dev, flags)
418 {
419 u_char unit = UNIT(dev),
420 part = PARTITION(dev);
421
422 if (!hdalive[unit] || part >= MAXPARTITIONS)
423 return(ENXIO);
424 getvtoc(unit);
425 if (!(label[unit].d_partitions[part].p_offset) &&
426 !(label[unit].d_partitions[part].p_size))
427 return(ENXIO);
428 return(0);
429 }
430
431 hdclose(dev)
432 {
433 return D_SUCCESS;
434 }
435
436 #ifdef MACH_KERNEL
437 /*
438 * No need to limit IO size to 4096 bytes.
439 */
440 int hdread(dev, ior)
441 dev_t dev;
442 io_req_t ior;
443 {
444 return (block_io(hdstrategy, minphys, ior));
445 }
446
447 int hdwrite(dev, ior)
448 dev_t dev;
449 io_req_t ior;
450 {
451 return (block_io(hdstrategy, minphys, ior));
452 }
453 #else MACH_KERNEL
454 hdminphys(bp)
455 struct buf *bp;
456 {
457 if (bp->b_bcount > PAGESIZ)
458 bp->b_bcount = PAGESIZ;
459 }
460
461 hdread(dev,uio)
462 dev_t dev;
463 struct uio *uio;
464 {
465 return(physio(hdstrategy,&hdbuf[UNIT(dev)],dev,B_READ,hdminphys,uio));
466 }
467
468 hdwrite(dev,uio)
469 dev_t dev;
470 struct uio *uio;
471 {
472 return(physio(hdstrategy,&hdbuf[UNIT(dev)],dev,B_WRITE,hdminphys,uio));
473 }
474 #endif MACH_KERNEL
475
476 #ifdef MACH_KERNEL
477 int abs_sec = -1;
478 int abs_count = -1;
479 /* IOC_OUT only and not IOC_INOUT */
480 io_return_t hdgetstat(dev, flavor, data, count)
481 dev_t dev;
482 int flavor;
483 int *data; /* pointer to OUT array */
484 unsigned int *count; /* OUT */
485 {
486 int unit = UNIT(dev);
487 struct disklabel *lp = &label[unit];
488 struct buf *bp1;
489 int i;
490
491 switch (flavor) {
492
493 /* Mandatory flavors */
494
495 case DEV_GET_SIZE: {
496 int part = PARTITION(dev);
497 data[DEV_GET_SIZE_DEVICE_SIZE] = lp->d_partitions[part].p_size * lp->d_secsize;
498 data[DEV_GET_SIZE_RECORD_SIZE] = lp->d_secsize;
499 *count = DEV_GET_SIZE_COUNT;
500 break;
501 }
502
503 /* BsdLabel flavors */
504 case DIOCGDINFO:
505 case DIOCGDINFO - (0x10<<16):
506 dkgetlabel(lp, flavor, data, count);
507 break;
508
509 /* Extra flavors */
510 case V_GETPARMS: {
511 struct disk_parms *dp;
512 int part = PARTITION(dev);
513 if (*count < sizeof (struct disk_parms)/sizeof(int))
514 return (D_INVALID_OPERATION);
515 dp = (struct disk_parms *) data;
516 dp->dp_type = DPT_WINI;
517 dp->dp_heads = lp->d_ntracks;
518 dp->dp_cyls = lp->d_ncylinders;
519 dp->dp_sectors = lp->d_nsectors;
520 dp->dp_dosheads = dosparm[unit].nheads;
521 dp->dp_doscyls = dosparm[unit].ncyl;
522 dp->dp_dossectors = dosparm[unit].nsec;
523 dp->dp_secsiz = lp->d_secsize;
524 dp->dp_ptag = 0;
525 dp->dp_pflag = 0;
526 dp->dp_pstartsec = lp->d_partitions[part].p_offset;
527 dp->dp_pnumsec = lp->d_partitions[part].p_size;
528 *count = sizeof(struct disk_parms)/sizeof(int);
529 break;
530 }
531 case V_RDABS: {
532 /* V_RDABS is relative to head 0, sector 0, cylinder 0 */
533 if (*count < SECSIZE/sizeof (int)) {
534 printf("hd%d: RDABS bad size %x", unit, count);
535 return (D_INVALID_OPERATION);
536 }
537 bp1 = geteblk(SECSIZE);
538 bp1->b_flags = B_READ | B_MD1; /* MD1 is be absolute */
539 bp1->b_blkno = abs_sec;
540 bp1->b_dev = WHOLE_DISK(unit); /* C partition */
541 bp1->b_bcount = SECSIZE;
542 hdstrategy(bp1);
543 biowait(bp1);
544 if (bp1->b_flags & B_ERROR) {
545 printf("hd%d hdsetstat(): read failure RDABS\n", unit);
546 brelse(bp1);
547 return (ENXIO);
548 }
549 bcopy(bp1->b_un.b_addr, (caddr_t)data, SECSIZE);
550 brelse(bp1);
551 *count = SECSIZE/sizeof(int);
552 break;
553 }
554 case V_VERIFY: {
555 unsigned int snum;
556 int xcount;
557 int code = 0;
558 bp1 = geteblk(PAGESIZ);
559 bp1->b_flags = B_READ;
560 bp1->b_blkno = abs_sec;
561 bp1->b_dev = WHOLE_DISK(unit); /* C partition */
562 xcount = abs_count;
563 snum = PAGESIZ >> 9;
564 while (xcount > 0) {
565 i = (xcount > snum) ? snum : xcount;
566 bp1->b_bcount = i << 9;
567 bp1->b_flags |= B_MD1;
568 hdstrategy(bp1);
569 biowait(bp1);
570 if (bp1->b_flags & B_ERROR) {
571 code = BAD_BLK;
572 break;
573 }
574 xcount -= i;
575 bp1->b_blkno += i;
576 bp1->b_flags &= ~B_DONE;
577 }
578 brelse(bp1);
579 data[0] = code;
580 *count = 1;
581 break;
582 }
583 default:
584 return (D_INVALID_OPERATION);
585 }
586 return (D_SUCCESS);
587 }
588
589 /* IOC_VOID or IOC_IN or IOC_INOUT */
590 io_return_t hdsetstat(dev, flavor, data, count)
591 dev_t dev;
592 int flavor;
593 int * data;
594 unsigned int count;
595 {
596 struct buf *bp1;
597 io_return_t errcode = D_SUCCESS;
598 int unit = UNIT(dev);
599 struct disklabel *lp = &label[unit];
600
601 switch (flavor) {
602 /* BsdLabel flavors */
603 case DIOCWLABEL:
604 case DIOCWLABEL - (0x10<<16):
605 if (*(int*)data)
606 /*
607 tgt->flags |= TGT_WRITE_LABEL;
608 else
609 tgt->flags &= ~TGT_WRITE_LABEL;
610 */ break;
611 case DIOCSDINFO:
612 case DIOCSDINFO - (0x10<<16):
613 case DIOCWDINFO:
614 case DIOCWDINFO - (0x10<<16):
615 if (count != sizeof(struct disklabel) / sizeof(int))
616 return D_INVALID_SIZE;
617 /*
618 * setdisklabel is in scsi/rz_disk.c; but is generic
619 */
620 errcode = setdisklabel(lp, (struct disklabel*) data);
621 if (errcode || (flavor == DIOCSDINFO) || (flavor == DIOCSDINFO - (0x10<<16)))
622 return errcode;
623 errcode = hdwritelabel(unit);
624 break;
625 /* LocalLabel flavors */
626 case V_REMOUNT:
627 hdgotvtoc[unit] = 0;
628 getvtoc(unit);
629 break;
630 case V_ABS:
631 abs_sec = *(int *)data;
632 if (count == 2)
633 abs_count = data[1];
634 break;
635 case V_WRABS:
636 /* V_WRABS is relative to head 0, sector 0, cylinder 0 */
637 if (count < SECSIZE/sizeof (int)) {
638 printf("hd%d: WRABS bad size %x", unit, count);
639 return (D_INVALID_OPERATION);
640 }
641 bp1 = geteblk(SECSIZE);
642 bcopy((caddr_t)data, bp1->b_un.b_addr, SECSIZE);
643 bp1->b_flags = B_WRITE | B_MD1; /* MD1 is be absolute */
644 bp1->b_blkno = abs_sec;
645 bp1->b_dev = WHOLE_DISK(unit); /* C partition */
646 bp1->b_bcount = SECSIZE;
647 hdstrategy(bp1);
648 biowait(bp1);
649 if (bp1->b_flags & B_ERROR) {
650 printf("hd%d: hdsetstat() read failure WRABS\n", unit);
651 errcode = ENXIO;
652 }
653 brelse(bp1);
654 break;
655 default:
656 return (D_INVALID_OPERATION);
657 }
658 return (errcode);
659 }
660
661 #else MACH_KERNEL
662 hdioctl(dev, cmd, arg, mode)
663 dev_t dev;
664 int cmd;
665 caddr_t arg;
666 {
667 u_char unit = UNIT(dev),
668 ctrl = unit>>1;
669 struct disklabel *lp = &label[unit];
670 union io_arg *arg_kernel;
671 int snum, xcount, i;
672 struct buf *bp1;
673
674 switch (cmd) {
675 case V_CONFIG:
676 arg_kernel = (union io_arg *)arg;
677 if (arg_kernel->ia_cd.secsiz != SECSIZE)
678 /* changing sector size NOT allowed */
679 return(EINVAL);
680 lp->d_ncylinders=(unsigned short)arg_kernel->ia_cd.ncyl;
681 lp->d_ntracks=(unsigned short)arg_kernel->ia_cd.nhead;
682 lp->d_nsectors=(unsigned short)arg_kernel->ia_cd.nsec;
683 fudge_bsd_label(lp, lp->d_type,
684 lp->d_ncylinders, lp->d_ntracks,
685 lp->d_nsectors, lp->d_npartitions);
686 setcontroller(unit);
687 break;
688 case V_REMOUNT:
689 hdgotvtoc[unit] = 0;
690 getvtoc(unit);
691 break;
692 case V_ADDBAD:
693 /* this adds a bad block to IN CORE alts table ONLY */
694 alt_info[unit].alt_sec.alt_used++;
695 alt_info[unit].alt_sec.alt_bad[alt_info[unit].alt_sec.alt_used]
696 = ((union io_arg *)arg)->ia_abs.bad_sector;
697 break;
698 case V_GETPARMS:
699 {
700 unsigned char part = PARTITION(dev);
701 struct disk_parms *disk_parms = (struct disk_parms *)arg;
702 disk_parms->dp_type = DPT_WINI;
703 disk_parms->dp_heads = lp->d_ntracks;
704 disk_parms->dp_cyls = lp->d_ncylinders;
705 disk_parms->dp_sectors = lp->d_nsectors
706 disk_parms->dp_dosheads = dosparm[unit].nheads;
707 disk_parms->dp_doscyls = dosparm[unit].ncyl;
708 disk_parms->dp_dossectors = dosparm[unit].nsec;
709 disk_parms->dp_secsiz = SECSIZE;
710 disk_parms->dp_ptag = 0;
711 disk_parms->dp_pflag = 0;
712 disk_parms->dp_pstartsec =lp->d_partitions[part].p_offset;
713 disk_parms->dp_pnumsec =lp->d_partitions[part].p_size;
714 break;
715 }
716 case V_RDABS:
717 /* V_RDABS is relative to head 0, sector 0, cylinder 0 */
718 bp1 = geteblk(SECSIZE);
719 bp1->b_flags = B_READ | B_MD1; /* MD1 is be absolute */
720 bp1->b_blkno = ((struct absio *)arg)->abs_sec;
721 bp1->b_dev = WHOLE_DISK(unit); /* C partition for RDABS */
722 bp1->b_bcount = SECSIZE;
723 hdstrategy(bp1);
724 biowait(bp1);
725 if (bp1->b_flags & B_ERROR) {
726 printf("hd: read failure on ioctl\n");
727 brelse(bp1);
728 return(ENXIO);
729 }
730 if(copyout(bp1->b_un.b_addr,((struct absio *)arg)->abs_buf,
731 SECSIZE)){
732 brelse(bp1);
733 return(ENXIO);
734 }
735 brelse(bp1);
736 break;
737 case V_WRABS:
738 /* V_WRABS is relative to head 0, sector 0, cylinder 0 */
739 bp1 = geteblk(SECSIZE);
740 if (copyin(((struct absio *)arg)->abs_buf,bp1->b_un.b_addr,
741 SECSIZE)){
742 brelse(bp1);
743 return(ENXIO);
744 }
745 bp1->b_flags = B_WRITE | B_MD1; /* MD1 is be absolute */
746 bp1->b_blkno = ((struct absio *)arg)->abs_sec;
747 bp1->b_dev = WHOLE_DISK(unit); /* C partition for RDABS */
748 bp1->b_bcount = SECSIZE;
749 hdstrategy(bp1);
750 biowait(bp1);
751 if (bp1->b_flags & B_ERROR) {
752 printf("hd: write failure on ioctl\n");
753 brelse(bp1);
754 return(ENXIO);
755 }
756 brelse(bp1);
757 break;
758 case V_VERIFY:
759 if (u.u_uid)
760 return(ENXIO);
761 bp1 = geteblk(PAGESIZ);
762 bp1->b_flags = B_READ | B_MD1;
763 bp1->b_blkno = ((union vfy_io *)arg)->vfy_in.abs_sec;
764 bp1->b_dev = WHOLE_DISK(unit); /* C partition for RDABS */
765 xcount = ((union vfy_io *)arg)->vfy_in.num_sec;
766 ((union vfy_io *)arg)->vfy_out.err_code = 0;
767 snum = PAGESIZ >> 9;
768 while (xcount > 0) {
769 i = (xcount > snum) ? snum : xcount;
770 bp1->b_bcount = i << 9;
771 hdstrategy(bp1);
772 biowait(bp1);
773 if (bp1->b_flags & B_ERROR) {
774 ((union vfy_io *)arg)->vfy_out.err_code=BAD_BLK;
775 break;
776 }
777 xcount -= i;
778 bp1->b_blkno += i;
779 bp1->b_flags &= ~B_DONE;
780 }
781 brelse(bp1);
782 break;
783 default:
784 return(EINVAL);
785 }
786 return(0);
787 }
788 #endif MACH_KERNEL
789
790 hdstrategy(bp)
791 struct buf *bp;
792 {
793 u_char unit = UNIT(bp->b_dev),
794 ctrl = unit>>1;
795 struct disklabel *lp = &label[unit];
796 struct partition *part_p = &lp->d_partitions[PARTITION(bp->b_dev)];
797 spl_t opri;
798
799 if (!bp->b_bcount)
800 goto done;
801 /* if request is off the end or trying to write last block on out */
802 if (bp->b_flags & B_MD1) {
803 if (bp->b_blkno > lp->d_partitions[PART_DISK].p_offset +
804 lp->d_partitions[PART_DISK].p_size - 1) {
805 bp->b_error = ENXIO;
806 goto bad;
807 }
808 } else {
809 if ((bp->b_blkno > part_p->p_size) ||
810 (bp->b_blkno==part_p->p_size && !(bp->b_flags & B_READ))) {
811 bp->b_error = ENXIO;
812 goto bad;
813 }
814 if (bp->b_blkno == part_p->p_size) {
815 /* indicate (read) EOF by setting b_resid to b_bcount on last block */
816 bp->b_resid = bp->b_bcount;
817 goto done;
818 }
819 }
820 bp->b_cylin = ((bp->b_flags&B_MD1 ? 0 : part_p->p_offset) + bp->b_blkno)
821 / (lp->d_nsectors * lp->d_ntracks);
822 opri = spl5();
823 disksort(&hdunit[unit], bp);
824 if (!hh[ctrl].controller_busy)
825 hdstart(ctrl);
826 splx(opri);
827 return;
828 bad:
829 bp->b_flags |= B_ERROR;
830 done:
831 iodone(bp);
832 return;
833 }
834
835 /* hdstart() is called at spl5 */
836 hdstart(ctrl)
837 int ctrl;
838 {
839 struct partition *part_p;
840 register struct buf *bp;
841 int i;
842
843 /* things should be quiet */
844 if (i = need_set_controller[ctrl]) {
845 if (i&1) set_controller(ctrl<<1);
846 if (i&2) set_controller((ctrl<<1)||1);
847 need_set_controller[ctrl] = 0;
848 }
849 if (bp = hdunit[hh[ctrl].curdrive^1].b_actf)
850 hh[ctrl].curdrive^=1;
851 else if (!(bp = hdunit[hh[ctrl].curdrive].b_actf))
852 return;
853 hh[ctrl].controller_busy = 1;
854 hh[ctrl].blocktotal = (bp->b_bcount + 511) >> 9;
855 part_p = &label[UNIT(bp->b_dev)].d_partitions[PARTITION(bp->b_dev)];
856 /* see V_RDABS and V_WRABS in hdioctl() */
857 if (bp->b_flags & B_MD1) {
858 struct disklabel *lp = &label[hh[ctrl].curdrive];
859 int end = lp->d_partitions[PART_DISK].p_offset +
860 lp->d_partitions[PART_DISK].p_size - 1;
861 hh[ctrl].physblock = bp->b_blkno;
862 if ((bp->b_blkno + hh[ctrl].blocktotal) > end)
863 hh[ctrl].blocktotal = end - bp->b_blkno + 1;
864 } else {
865 hh[ctrl].physblock = part_p->p_offset + bp->b_blkno;
866 if ((bp->b_blkno + hh[ctrl].blocktotal) > part_p->p_size)
867 hh[ctrl].blocktotal = part_p->p_size - bp->b_blkno + 1;
868 }
869 hh[ctrl].blockcount = 0;
870 hh[ctrl].rw_addr = (int)bp->b_un.b_addr;
871 hh[ctrl].retry_count = 0;
872 start_rw(bp->b_flags & B_READ, ctrl);
873 }
874
875 int hd_print_error = 0;
876 hdintr(ctrl)
877 int ctrl;
878 {
879 register struct buf *bp;
880 int addr = devaddr[ctrl],
881 unit = hh[ctrl].curdrive;
882 u_char status;
883
884 if (!hh[ctrl].controller_busy)
885 return;
886 waitcontroller(ctrl);
887 status = inb(PORT_STATUS(addr));
888 bp = hdunit[unit].b_actf;
889 if (hh[ctrl].restore_request) { /* Restore command has completed */
890 hh[ctrl].restore_request = 0;
891 if (status & STAT_ERROR)
892 hderror(bp,ctrl);
893 else if (bp)
894 start_rw(bp->b_flags & B_READ,ctrl);
895 return;
896 }
897 if (status & STAT_WRITEFAULT) {
898 if (hd_print_error) {
899 printf("hdintr: write fault. block %d, count %d, total %d\n",
900 hh[ctrl].physblock, hh[ctrl].blockcount,
901 hh[ctrl].blocktotal);
902 printf("hdintr: write fault. cyl %d, head %d, sector %d\n",
903 hh[ctrl].cylinder, hh[ctrl].head,
904 hh[ctrl].sector);
905
906 }
907 panic("hd: write fault\n");
908 }
909 if (status & STAT_ERROR) {
910 if (hd_print_error) {
911 printf("hdintr: state error %x, error = %x\n",
912 status, inb(PORT_ERROR(addr)));
913 printf("hdintr: state error. block %d, count %d, total %d\n",
914 hh[ctrl].physblock, hh[ctrl].blockcount,
915 hh[ctrl].blocktotal);
916 printf("hdintr: state error. cyl %d, head %d, sector %d\n",
917 hh[ctrl].cylinder, hh[ctrl].head,
918 hh[ctrl].sector);
919
920 }
921 hderror(bp,ctrl);
922 return;
923 }
924 if (status & STAT_ECC)
925 printf("hd: ECC soft error fixed, unit %d, partition %d, physical block %d \n",
926 unit, PARTITION(bp->b_dev), hh[ctrl].physblock);
927 if (!bp) {
928 /* there should be a read/write buffer queued at this point */
929 printf("hd%d: no bp buffer to read or write\n",unit);
930 return;
931 }
932 if (bp->b_flags & B_READ) {
933 while (!(inb(PORT_STATUS(addr)) & STAT_DATAREQUEST));
934 linw(PORT_DATA(addr), hh[ctrl].rw_addr, SECSIZE/2);
935 }
936 if (++hh[ctrl].blockcount == hh[ctrl].blocktotal) {
937 hdunit[unit].b_actf = bp->av_forw;
938 bp->b_resid = 0;
939 iodone(bp);
940 hh[ctrl].controller_busy = 0;
941 hdstart(ctrl);
942 } else {
943 hh[ctrl].rw_addr += SECSIZE;
944 hh[ctrl].physblock++;
945 if (hh[ctrl].single_mode)
946 start_rw(bp->b_flags & B_READ,ctrl);
947 else if (!(bp->b_flags & B_READ)) {
948 /* Load sector into controller for next write */
949 while (!(inb(PORT_STATUS(addr)) & STAT_DATAREQUEST));
950 loutw(PORT_DATA(addr), hh[ctrl].rw_addr, SECSIZE/2);
951 }
952 }
953 }
954
955 hderror(bp,ctrl)
956 struct buf *bp;
957 int ctrl;
958 {
959 int addr = devaddr[ctrl],
960 unit = hh[ctrl].curdrive;
961
962 if(++hh[ctrl].retry_count > 3) {
963 if(bp) {
964 int i;
965 /****************************************************
966 * We have a problem with this block, set the error *
967 * flag, terminate the operation and move on to the *
968 * next request. With every hard disk transaction *
969 * error we set the reset requested flag so that the *
970 * controller is reset before the next operation is *
971 * started. *
972 ****************************************************/
973 hdunit[unit].b_actf = bp->av_forw;
974 bp->b_flags |= B_ERROR;
975 bp->b_resid = 0;
976 iodone(bp);
977 outb(FIXED_DISK_REG(ctrl), 4);
978 for(i = 0; i < 10000; i++);
979 outb(FIXED_DISK_REG(ctrl), 0);
980 setcontroller(unit);
981 hh[ctrl].controller_busy = 0;
982 hdstart(ctrl);
983 }
984 }
985 else {
986 /* lets do a recalibration */
987 waitcontroller(ctrl);
988 hh[ctrl].restore_request = 1;
989 outb(PORT_PRECOMP(addr), dosparm[unit].precomp>>2);
990 outb(PORT_NSECTOR(addr), label[unit].d_nsectors);
991 outb(PORT_SECTOR(addr), hh[ctrl].sector);
992 outb(PORT_CYLINDERLOWBYTE(addr), hh[ctrl].cylinder & 0xff);
993 outb(PORT_CYLINDERHIBYTE(addr), (hh[ctrl].cylinder>>8) & 0xff);
994 outb(PORT_DRIVE_HEADREGISTER(addr), (unit&1)<<4);
995 outb(PORT_COMMAND(addr), CMD_RESTORE);
996 }
997 }
998
999 getvtoc(unit)
1000 {
1001 hdreadlabel(unit, 1);
1002 }
1003
1004 setcontroller(unit)
1005 {
1006 need_set_controller[unit>>1] |= (1<<(unit&1));
1007 }
1008
1009 set_controller(unit)
1010 {
1011 int ctrl = unit >> 1;
1012 int addr = devaddr[ctrl];
1013 struct disklabel *lp = &label[unit];
1014
1015 waitcontroller(ctrl);
1016 outb(PORT_DRIVE_HEADREGISTER(addr), (lp->d_ntracks - 1) |
1017 ((unit&1) << 4) | FIXEDBITS);
1018 outb(PORT_NSECTOR(addr), lp->d_nsectors);
1019 outb(PORT_COMMAND(addr), CMD_SETPARAMETERS);
1020 waitcontroller(ctrl);
1021 }
1022
1023 waitcontroller(ctrl)
1024 {
1025 u_int n = PATIENCE;
1026
1027 while (--n && inb(PORT_STATUS(devaddr[ctrl])) & STAT_BUSY);
1028 if (n)
1029 return;
1030 panic("hd%d: waitcontroller() timed out",ctrl);
1031 }
1032
1033 start_rw(read, ctrl)
1034 int read, ctrl;
1035 {
1036 int addr = devaddr[ctrl],
1037 unit = hh[ctrl].curdrive;
1038 struct disklabel *lp = &label[unit];
1039 u_int track, disk_block, xblk;
1040
1041 disk_block = hh[ctrl].physblock;
1042 xblk=hh[ctrl].blocktotal - hh[ctrl].blockcount; /*# blks to transfer*/
1043 if (!(hdunit[unit].b_actf->b_flags & B_MD1) &&
1044 (hh[ctrl].single_mode = xfermode(ctrl))) {
1045 xblk = 1;
1046 if (PARTITION(hdunit[unit].b_actf->b_dev) != PART_DISK)
1047 disk_block = badblock_mapping(ctrl);
1048 }
1049 /* disk is formatted starting sector 1, not sector 0 */
1050 hh[ctrl].sector = (disk_block % lp->d_nsectors) + 1;
1051 track = disk_block / lp->d_nsectors;
1052 hh[ctrl].head = track % lp->d_ntracks |
1053 (unit&1) << 4 | FIXEDBITS;
1054 hh[ctrl].cylinder = track / lp->d_ntracks;
1055 waitcontroller(ctrl);
1056 outb(PORT_PRECOMP(addr), dosparm[unit].precomp >>2);
1057 outb(PORT_NSECTOR(addr), xblk);
1058 outb(PORT_SECTOR(addr), hh[ctrl].sector);
1059 outb(PORT_CYLINDERLOWBYTE(addr), hh[ctrl].cylinder & 0xff );
1060 outb(PORT_CYLINDERHIBYTE(addr), (hh[ctrl].cylinder >> 8) & 0xff );
1061 outb(PORT_DRIVE_HEADREGISTER(addr), hh[ctrl].head);
1062 if(read) {
1063 outb(PORT_COMMAND(addr), CMD_READ);
1064 } else {
1065 outb(PORT_COMMAND(addr), CMD_WRITE);
1066 waitcontroller(ctrl);
1067 while (!(inb(PORT_STATUS(addr)) & STAT_DATAREQUEST));
1068 loutw(PORT_DATA(addr), hh[ctrl].rw_addr, SECSIZE/2);
1069 }
1070 }
1071
1072 int badblock_mapping(ctrl)
1073 int ctrl;
1074 {
1075 u_short n;
1076 u_int track,
1077 unit = hh[ctrl].curdrive,
1078 block = hh[ctrl].physblock,
1079 nsec = label[unit].d_nsectors;
1080
1081 track = block / nsec;
1082 for (n = 0; n < alt_info[unit].alt_trk.alt_used; n++)
1083 if (track == alt_info[unit].alt_trk.alt_bad[n])
1084 return alt_info[unit].alt_trk.alt_base +
1085 nsec * n + (block % nsec);
1086 /* BAD BLOCK MAPPING */
1087 for (n = 0; n < alt_info[unit].alt_sec.alt_used; n++)
1088 if (block == alt_info[unit].alt_sec.alt_bad[n])
1089 return alt_info[unit].alt_sec.alt_base + n;
1090 return block;
1091 }
1092
1093 /*
1094 * determine single block or multiple blocks transfer mode
1095 */
1096 int xfermode(ctrl)
1097 int ctrl;
1098 {
1099 int n, bblk, eblk, btrk, etrk;
1100 int unit = hh[ctrl].curdrive;
1101
1102 bblk = hh[ctrl].physblock;
1103 eblk = bblk + hh[ctrl].blocktotal - 1;
1104 btrk = bblk / label[unit].d_nsectors;
1105 etrk = eblk / label[unit].d_nsectors;
1106
1107 for (n = 0; n < alt_info[unit].alt_trk.alt_used; n++)
1108 if ((btrk <= alt_info[unit].alt_trk.alt_bad[n]) &&
1109 (etrk >= alt_info[unit].alt_trk.alt_bad[n]))
1110 return 1;
1111 for (n = 0; n < alt_info[unit].alt_sec.alt_used; n++)
1112 if ((bblk <= alt_info[unit].alt_sec.alt_bad[n]) &&
1113 (eblk >= alt_info[unit].alt_sec.alt_bad[n]))
1114 return 1;
1115 return 0;
1116 }
1117
1118 hdsize()
1119 {
1120 printf("hdsize() -- not implemented\n");
1121 }
1122
1123 hddump()
1124 {
1125 printf("hddump() -- not implemented\n");
1126 }
1127
1128 #ifdef MACH_KERNEL
1129 /*
1130 * Routine to return information to kernel.
1131 */
1132 int
1133 hddevinfo(dev, flavor, info)
1134 dev_t dev;
1135 int flavor;
1136 char *info;
1137 {
1138 register int result;
1139
1140 result = D_SUCCESS;
1141
1142 switch (flavor) {
1143 case D_INFO_BLOCK_SIZE:
1144 *((int *) info) = SECSIZE;
1145 break;
1146 default:
1147 result = D_INVALID_OPERATION;
1148 }
1149
1150 return(result);
1151 }
1152 #endif MACH_KERNEL
Cache object: 807367d4b01cc5ae9e5030c7319bd92a
|