FreeBSD/Linux Kernel Cross Reference
sys/i386ps2/hd.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1989 Carnegie Mellon University
4 * Copyright (c) 1991 IBM Corporation
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation,
12 * and that the name IBM not be used in advertising or publicity
13 * pertaining to distribution of the software without specific, written
14 * prior permission.
15 *
16 * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie Mellon
28 * the rights to redistribute these changes.
29 */
30
31 static char sccsid[] = "@(#)66 1.1 mk/src/latest/kernel/i386ps2/hd.c, root 4/4/91 10:22:11";
32 /*
33 * HISTORY
34 * $Log: hd.c,v $
35 * Revision 2.5 93/08/10 16:00:26 mrt
36 * changed partition -> localpartition for type declaration so not
37 * to conflict with partition struct introduced in disklabel.h
38 * [93/08/09 rvb]
39 *
40 * Revision 2.4 93/05/28 21:22:25 rvb
41 * In the getstat and setstat routines, return failure
42 * if the flavor isn't one we know about.
43 * [93/05/28 15:07:28 chs]
44 *
45 * Revision 2.3 93/03/11 14:09:19 danner
46 * u_long -> u_int
47 * [93/03/09 danner]
48 *
49 * Revision 2.2 93/02/04 07:59:55 danner
50 * Using i386at/disk.h rather than i386ps2/disk.h == They are
51 * identical.
52 * [93/01/25 rvb]
53 *
54 * Changed to new partition scheme.
55 * Pick up recent bugfixes from i386at/hd.c.
56 * [93/01/18 zon]
57 *
58 * Integrate PS2 code from IBM.
59 * [93/01/18 prithvi]
60 *
61 * Revision 1.17 90/11/02 11:15:42 webb
62 * 1. move code out of hdinit into hdprobe and hdslave routines
63 * 2. make other appropriate changes to work fully with autoconfig.
64 *
65 * Revision 1.16 90/11/01 10:44:52 webb
66 * changes for new version of config
67 *
68 * Revision 1.15 90/10/23 15:36:13 webb
69 * remove dead code and make changes so that multiple LIDS (and multiple
70 * interrupt vectors) are supported.
71 *
72 * Revision 1.7 90/09/12 11:10:09 webb
73 * 1. clean up code and debugging printf's
74 * 2. improve error message output's
75 * 3. delete code not needed for this driver
76 * 4. put in error retrying
77 *
78 * Revision 1.6 90/09/05 10:00:47 webb
79 * 1. add error decoding
80 * 2. use write-verify instead of write for now
81 * 3. allow driver to return an error instead of just panicing.
82 *
83 * Revision 1.4 90/08/16 15:51:32 relyea
84 * rci.rsc nps2 hdreg.h
85 * fix problems which blew GCC out of the water.
86 *
87 * Revision 1.3 90/08/08 11:20:18 webb
88 * changes to make gcc happy.
89 *
90 * Revision 1.1 90/02/23 00:27:20 devrcs
91 * Latest version for osc.5
92 * [90/02/20 11:57:26 kevins]
93 *
94 * Revision 1.6 89/10/24 20:20:52 lance
95 * Trying to fix the random hang bug.
96 *
97 * Revision 1.5 89/09/26 11:56:47 lance
98 * X109 checkin
99 *
100 * Revision 1.8 89/09/25 12:26:48 rvb
101 * i386at/alttbl.h, i386/vtoc.h, i386/iobuf.h, i386/elog.h -> disk.h
102 * [89/09/23 rvb]
103 *
104 * Revision 1.7 89/09/20 17:28:21 rvb
105 * Revision 1.3 89/08/01 16:54:04 kupfer
106 * Debugging hacks for when driver gets wedged.
107 *
108 * Revision 1.2 89/07/12 11:13:41 lance
109 * New paths to disk (both through buffer cache & physio).
110 *
111 * Revision 1.4 89/03/09 20:05:37 rpd
112 * More cleanup.
113 *
114 * Revision 1.3 89/02/26 12:36:37 gm0w
115 * Changes for cleanup.
116 *
117 */
118
119 /*
120 * INTEL CORPORATION PROPRIETARY INFORMATION
121 *
122 * This software is supplied under the terms of a license
123 * agreement or nondisclosure agreement with Intel Corpo-
124 * ration and may not be copied or disclosed except in
125 * accordance with the terms of that agreement.
126 * Copyright 1988 Intel Corporation.
127 */
128
129 /*
130 * AT Hard Disk Driver
131 * Copyright Ing. C. Olivetti & S.p.A. 1989
132 * All rights reserved.
133 *
134 */
135
136 #include <platforms.h>
137 #include <hd.h>
138
139 #if NHD > 0
140
141 #include <sys/types.h>
142 #define PRIBIO 20
143 #include <device/io_req.h>
144 #include <device/buf.h>
145 #include <device/errno.h>
146 #include <device/device_types.h>
147 #include <device/disk_status.h>
148
149 typedef long paddr_t; /* a physical address */
150
151 #include <sys/ioctl.h>
152 #include <i386/ipl.h>
153 #include <i386ps2/bus.h>
154 #include <i386ps2/abios.h>
155 #include <i386ps2/debugf.h>
156 #include <i386ps2/gdabios.h>
157 #include <i386ps2/hdreg.h>
158 #include <i386at/disk.h>
159
160 #define LABEL_DEBUG(x,y) if (label_flag&x) y
161
162 extern struct buf *geteblk();
163
164 #ifndef NHDC
165 #define NHDC 1 /* for systems without a full config */
166 #endif
167
168 #define ABIOS_WRITE_VERIFY ABIOS_ADDITIONAL_XFER
169 #define B_RESET 0x10000000 /* resetting the disk */
170
171 struct hh hh;
172 struct buf hd_buF[NHD]; /* buffer for raw io */
173 struct buf hdunit[NHD];
174 struct alt_info alt_info[NHD];
175
176 int hdgotvtoc[NHD];
177
178 #define HD_MAX_XFER (I386_PGBYTES * 8)
179 static char unaligned_buf[NHD][HD_MAX_XFER]; /* buffer for unaligned xfers */
180 static caddr_t u_buf[NHD]; /* pointer to the buffer */
181 static struct buf *bp1, *bp2;
182 static struct Gd_request rb[NHD];
183 static struct Gd_request ctlr_rb[NHDC];
184 static struct Gd_request save_rb[NHD];
185 struct disklabel label[NHD];
186 int labeloffset[NHD];
187 int labelsector[NHD];
188 static hdisk_t hdparams[NHD];
189 static saveaddr_t save_addr[NHD][34];
190 static struct Logical_id_params params = {0};
191
192 int hd_write_verify = 0; /* will we use write-verify function? */
193
194 static void start_rw(long read);
195 static int hdintr(int vec);
196 static int hdabioswait(int abios_function, int gd_flag, int unit);
197 int hdstrategy(struct buf *);
198 static void hdinit(void);
199 static hd_error_decode(int code, char *msg);
200
201 static int hdprobe();
202 static int hdslave();
203 static int hdattach();
204
205 int (*hdcintrs[])(int) = {hdintr, 0};
206
207 static struct i386_dev *hdinfo[NHD];
208 static struct i386_ctlr *hdcinfo[NHDC];
209
210 #define WHOLE_DISK(unit) ((unit << 4) + PART_DISK)
211
212 struct i386_driver hdcdriver = {
213 /* probe slave attach dname dinfo mname minfo */
214 hdprobe, hdslave, hdattach, "hd", hdinfo, "hdc", hdcinfo};
215
216 #define DEV_CTRL_FLAGS_FMT "\2\3CHANGE-SIGNAL\4WRITE-MANY\5CACHING\6READABLE\7LOCKABLE\10SEQUENTIAL\11EJECTABLE\12CONCURRENT\13ST506\14FORMAT-TRACK\15FORMAT-UNIT\17SCSI\20SCB"
217 #define LOGICAL_ID_FLAGS_FMT "\2\1DATA-POINTER1-LOGICAL\2DATA-POINTER2-PHYSICAL\4OVERLAPPED-IO"
218
219 /*
220 * probe for the specified controller.
221 * we look for the n'th (actually stored in unit) hard disk LID.
222 * if not found we return that the device doesn't exist.
223 * if found we get the information about that controller.
224 * we use "rb" as a working area, and copy the results back
225 * into ctlr_rb after we are finished. This is mainly so that we
226 * don't have to change abioswait to accept a request block parameter.
227 */
228 static int hdprobe(addr, ctlr)
229 int addr;
230 struct i386_ctlr *ctlr;
231 {
232 int lid_num = 2; /* starting lid number */
233 int i;
234 int unit = ctlr->ctlr_ctlr;
235 static intr_num = -1; /* avoid duplicating interrupt handlers */
236 struct Gd_request *rbp = &rb[unit];
237
238 hdinit(); /* do other initializations */
239
240 /*
241 * scan thru the available abios devices looking for this
242 * controller (unit) number.
243 */
244 for (i=0; (lid_num = abios_next_LID(HD_ID, lid_num)) && i < unit; ++i);
245
246 if (lid_num == 0)
247 return 0; /* no such LID */
248
249 /*
250 * at this point we have determined that the requested controller
251 * (e.g. LID) exists.
252 */
253
254 rbp->r_current_req_blck_len = sizeof(struct Gd_request);
255 rbp->request_header.Request_Block_Flags = 0;
256 rbp->request_header.ELA_Offset = 0;
257
258 GD_SET_RESERVED_ABIOS_LOGICAL_PARAMETER(*rbp);
259 rbp->r_logical_id = lid_num;
260 rbp->r_unit = 0;
261
262 if (hdabioswait(ABIOS_LOGICAL_PARAMETER, params.Logical_id_flags, unit))
263 return ENXIO;
264
265 params = rbp->un.logical_id_params;
266
267 /*
268 * Now we need to update certain field based on what ABIOS
269 * just told us...
270 */
271
272 if (rbp->r_request_block_length > rbp->r_current_req_blck_len) {
273 printf("hdc%d: Required Request block length is too large.\n",unit);
274 return(0);
275 }
276
277 rbp->r_current_req_blck_len = rbp->r_request_block_length;
278
279 if (!(params.Logical_id_flags & 0x2)) {
280 printf ("hdc%d: can not support virtual addresses.\n", unit);
281 return(0);
282 }
283
284 /* if we haven't already gotten this IRQ then obtain it */
285 if (intr_num != rbp->r_hardware_intr) {
286 ctlr->ctlr_pic = intr_num = rbp->r_hardware_intr;
287 ctlr->ctlr_spl = SPL5;
288 take_ctlr_irq(ctlr);
289 printf("hdc%d: port = %x, spl = %d, pic = %d.\n",
290 ctlr->ctlr_ctlr, ctlr->ctlr_addr, ctlr->ctlr_spl, ctlr->ctlr_pic);
291 }
292
293 ctlr_rb[unit] = *rbp; /* save controller's rb */
294
295 return 1;
296
297 }
298
299 /*
300 * see if this unit exists and if it does get the information about it.
301 */
302 static int hdslave(iod)
303 struct i386_dev *iod;
304 {
305 int unit = iod->dev_unit;
306 int slave = iod->dev_slave;
307
308 if (slave >= ctlr_rb[iod->dev_ctlr].r_number_units)
309 return(0); /* not that many units */
310
311 rb[unit] = ctlr_rb[iod->dev_ctlr]; /* copy from controller */
312 rb[unit].r_unit = slave;
313 hdunit[unit].b_active = 0;
314 hdunit[unit].b_actf = 0;
315 hdunit[unit].b_actl = 0;
316 hdparams[unit].landzone = 0;
317 hdparams[unit].precomp = 0;
318 hdparams[unit].lid = rb[unit].r_logical_id;
319 hdparams[unit].unit = slave;
320 GD_SET_RESERVED_ABIOS_READ_PARAMETER(rb[unit]);
321
322 if (hdabioswait(ABIOS_READ_PARAMETER, params.Logical_id_flags, unit))
323 return(0);
324
325 hdparams[unit].ncylinders = gd_number_cylinders(rb[unit]);
326 hdparams[unit].nheads = gd_number_heads(rb[unit]);
327 hdparams[unit].nblocks = gd_max_block_number(rb[unit]);
328 hdparams[unit].nsecpertrack = gd_sector_per_track(rb[unit]);
329 hdparams[unit].flags = gd_dev_ctrl_flag(rb[unit]);
330 hdparams[unit].retries = gd_max_retries(rb[unit]);
331 hdparams[unit].max_transfer = gd_max_transfer(rb[unit]);
332 /*
333 * copy initial parameters into label
334 */
335 fudge_bsd_label(&label[unit], DTYPE_ESDI,
336 hdparams[unit].ncylinders,
337 hdparams[unit].nheads,
338 hdparams[unit].nsecpertrack,
339 2);
340
341 printf("hd%d: ncylinders=%d nheads=%d nsecpertrack=%d nblocks=%d\n",
342 unit,
343 hdparams[unit].ncylinders,
344 hdparams[unit].nheads,
345 hdparams[unit].nsecpertrack,
346 hdparams[unit].nblocks);
347
348 hh.num_units++; /* accumulate total number of units */
349 params.Device_id = rb[unit].r_logical_id;;
350
351 return(1);
352 }
353
354 static hdattach(iod)
355 struct i386_dev *iod;
356 {
357 }
358
359 /*
360 * initialize the disk.
361 */
362 static void hdinit(void)
363 {
364 int i;
365 static int hdinit_done = 0;
366
367 if (hdinit_done++)
368 return;
369
370 for (i = 0; i < NHD; i++)
371 u_buf[i] = &unaligned_buf[i][0];
372 hh.un_aligned = 0;
373
374 }
375
376 static void hd_delay(register int ticks)
377 {
378 assert_wait(0, FALSE);
379 thread_set_timeout(ticks);
380 thread_block((continuation_t) 0);
381 }
382
383 static int hdabioswait(int abios_function, int gd_flag, int unit)
384 {
385 int i, j, n;
386
387 struct Gd_request *rbp = &rb[unit];
388
389 rbp->r_function = abios_function;
390 rbp->r_return_code = ABIOS_UNDEFINED;
391
392 abios_common_start(rbp, gd_flag);
393
394 /* Wait for ABIOS to tell us that it is done. */
395 while (rbp->r_return_code == ABIOS_UNDEFINED)
396 hd_delay(10);
397
398 if (rbp->r_return_code & 0x8000) {
399 printf("[hdabioswait] rb[unit].r_return_code [%x] ", rbp->r_return_code);
400 hd_error_decode(rbp->r_return_code, "\n");
401 return ENXIO;
402 }
403
404 hh.status = rbp->r_return_code;
405
406 while (rbp->r_return_code != ABIOS_DONE) {
407
408 hh.status = rbp->r_return_code;
409
410 switch (hh.status) {
411
412 case ABIOS_STAGE_ON_INT:
413 hd_delay(1);
414 break;
415
416 case ABIOS_STAGE_ON_TIME:
417 hd_delay(gd_wait_time(*rbp));
418 abios_common_interrupt(rbp, params.Logical_id_flags);
419 break;
420
421 case (ABIOS_NOT_MY_INT | ABIOS_STAGE_ON_INT):
422 break;
423
424 case ABIOS_DONE:
425 return;
426
427 default:
428 printf("hdabioswait: return code [%x]...\n", hh.status);
429 hd_error_decode(rbp->r_return_code,"\n");
430 return ENXIO;
431 }
432 }
433
434 return 0;
435
436 }
437 getvtoc(unit)
438 {
439 hdreadlabel(unit, 0);
440 }
441
442 static hdreset(int unit)
443 {
444 struct buf *bp = (struct buf *)geteblk(SECSIZE);
445
446 #if 0
447 if (label[unit].d_partitions[PART_DISK].p_tag == 0) {
448 label[unit].d_partitions[PART_DISK].p_tag = V_BACKUP;
449 label[unit].d_partitions[PART_DISK].p_flag = V_OPEN | V_UNMNT | V_VALID;
450 label[unit].d_partitions[PART_DISK].p_offset = 0;
451 label[unit].d_partitions[PART_DISK].p_size = 10;
452 }
453 #endif /* 0 */
454
455 bp->b_flags = B_RESET|B_MD1;
456 bp->b_blkno = 0;
457 bp->b_dev = WHOLE_DISK(unit);
458 bp->b_bcount = 0;
459 hdstrategy(bp);
460 biowait(bp);
461
462 getvtoc(unit);
463
464 }
465
466 io_return_t hdopen(register dev_t dev,
467 register dev_mode_t flags,
468 io_req_t not_used)
469 {
470 int unit = UNIT(dev);
471 int part = PARTITION(dev);
472 int n;
473 static int hdopen_done = 0;
474
475 if (part >= MAXPARTITIONS || unit >= NHD)
476 return ENXIO;
477
478 if (!hdopen_done++) {
479 hdinit();
480 for (n = 0; n < hh.num_units; n++)
481 hdreset(n);
482 }
483
484 if (!label[unit].d_partitions[part].p_offset &&
485 !label[unit].d_partitions[part].p_size)
486 return ENXIO;
487
488 return D_SUCCESS;
489
490 }
491
492
493 io_return_t hdclose(register dev_t dev)
494 {
495
496 return D_SUCCESS;
497
498 }
499
500 int hdread(register dev_t dev, register struct uio *uio)
501 {
502 register struct buf *bp = &hd_buF[UNIT(dev)];
503
504 return physio(hdstrategy, bp, dev, B_READ, minphys, uio);
505
506 }
507
508 int hdwrite(register dev_t dev, register struct uio *uio)
509 {
510 register struct buf *bp = &hd_buF[UNIT(dev)];
511
512 return physio(hdstrategy, bp, dev, B_WRITE, minphys, uio);
513
514 }
515
516 static int abs_sec = -1;
517 static int abs_count = -1;
518
519 io_return_t hdgetstat(dev, flavor, data, count)
520 dev_t dev;
521 int flavor;
522 int * data; /* pointer to OUT array */
523 unsigned int *count; /* OUT */
524 {
525 int unit = UNIT(dev);
526 struct disklabel *lp = &label[unit];
527 int part = PARTITION(dev);
528 io_return_t errcode = D_SUCCESS;
529 struct disk_parms *dp;
530 unsigned int snum;
531 int xcount, i;
532 int code;
533
534
535 switch (flavor) {
536
537 case DEV_GET_SIZE:
538 data[DEV_GET_SIZE_DEVICE_SIZE] =
539 lp->d_partitions[part].p_size * lp->d_secsize;
540 data[DEV_GET_SIZE_RECORD_SIZE] = lp->d_secsize;
541 *count = DEV_GET_SIZE_COUNT;
542 break;
543
544 /* BsdLabel flavors */
545 case DIOCGDINFO:
546 case DIOCGDINFO - (0x10<<16):
547 dkgetlabel(lp, flavor, data, count);
548 break;
549
550 /* Extra flavors */
551 case V_GETPARMS:
552 if (*count < sizeof (struct disk_parms)/sizeof(int)) {
553 printf("hd%d%c: V_GETPARMS bad size %x",
554 unit,
555 'a' + part,
556 count);
557 return D_INVALID_OPERATION;
558 }
559 dp = (struct disk_parms *) data;
560 dp->dp_type = DPT_WINI;
561 dp->dp_heads = lp->d_ntracks;
562 dp->dp_cyls = lp->d_ncylinders;
563 dp->dp_sectors = lp->d_nsectors;
564 dp->dp_dosheads = hdparams[unit].nheads;
565 dp->dp_doscyls = hdparams[unit].ncylinders;
566 dp->dp_dossectors = hdparams[unit].nsecpertrack;
567 dp->dp_secsiz = SECSIZE;
568 dp->dp_ptag = 0 /* label[unit].d_partitions[part].p_tag */;
569 dp->dp_pflag = 0 /* label[unit].d_partitions[part].p_flag */;
570 dp->dp_pstartsec = label[unit].d_partitions[part].p_offset;
571 dp->dp_pnumsec =label[unit].d_partitions[part].p_size;
572 *count = sizeof (struct disk_parms)/sizeof(int);
573 break;
574
575 case V_PDLOC:
576 *data = label[unit].d_partitions[PART_DISK].p_offset + PDLOCATION;
577 break;
578
579 case V_RDABS:
580 if (*count < SECSIZE/sizeof (int)) {
581 printf("hd%d: V_RDABS bad size %x",
582 unit,
583 count);
584 return D_INVALID_OPERATION;
585 }
586 bp1 = geteblk(SECSIZE);
587 bp1->b_flags = B_READ | B_MD1;
588 bp1->b_blkno = abs_sec;
589 bp1->b_dev = WHOLE_DISK(unit);
590 bp1->b_bcount = SECSIZE;
591 hdstrategy(bp1);
592 biowait(bp1);
593 if (bp1->b_flags & B_ERROR) {
594 printf("hd%d: V_RDABS failed\n", unit);
595 errcode = ENXIO;
596 brelse(bp1);
597 break;
598 }
599 bcopy((caddr_t)paddr(bp1), (caddr_t) data, SECSIZE);
600 brelse(bp1);
601 *count = SECSIZE/sizeof(int);
602 break;
603
604 case V_VERIFY:
605 bp1 = geteblk(PAGESIZ);
606 bp1->b_flags = B_READ | B_MD1;
607 bp1->b_blkno = abs_sec;
608 bp1->b_dev = WHOLE_DISK(unit);
609 xcount = abs_count;
610 snum = PAGESIZ >> 9;
611 code = 0;
612 while (xcount > 0) {
613 i = (xcount > snum) ? snum : xcount;
614 bp1->b_bcount = i << 9;
615 hdstrategy(bp1);
616 biowait(bp1);
617 if (bp1->b_flags & B_ERROR) {
618 code = BAD_BLK;
619 break;
620 }
621 xcount -= i;
622 bp1->b_blkno += i;
623 bp1->b_flags &= ~B_DONE;
624 }
625 brelse(bp1);
626 data[0] = code;
627 *count = 1;
628 break;
629
630 default:
631 return D_INVALID_OPERATION;
632 }
633
634 return errcode;
635
636 }
637
638 io_return_t hdsetstat(dev_t dev, int flavor, int *data, unsigned int count)
639 {
640 io_return_t errcode = D_SUCCESS;
641 int unit = UNIT(dev);
642 struct disklabel*lp = &label[unit];
643 int part = PARTITION(dev);
644
645 switch (flavor) {
646 /* BsdLabel flavors */
647 case DIOCWLABEL:
648 case DIOCWLABEL - (0x10<<16):
649 case DIOCSDINFO:
650 case DIOCSDINFO - (0x10<<16):
651 case DIOCWDINFO:
652 case DIOCWDINFO - (0x10<<16):
653 return hdsetlabel(dev, flavor, data, count);
654
655 /* LocalLabel flavors */
656 case V_REMOUNT:
657 hdgotvtoc[unit] = 0;
658 getvtoc(unit);
659 break;
660
661 case V_ABS:
662 abs_sec = *(int *)data;
663 if (count == 2)
664 abs_count = data[1];
665 break;
666
667 case V_WRABS:
668 if (count < 512/sizeof (int)) {
669 printf("hdsetstat: hd%d WRABS bad size %x",
670 unit,
671 count);
672 return D_INVALID_OPERATION;
673 }
674 bp1 = geteblk(SECSIZE);
675 bcopy( (caddr_t)data, (caddr_t)paddr(bp1), SECSIZE);
676 bp1->b_flags = B_WRITE | B_MD1;
677 bp1->b_blkno = abs_sec;
678 bp1->b_dev = WHOLE_DISK(unit);
679 bp1->b_bcount = SECSIZE;
680 hdstrategy(bp1);
681 biowait(bp1);
682 if (bp1->b_flags & B_ERROR) {
683 printf("hdsetstat: hd%d WRABS failed\n", unit);
684 errcode = ENXIO;
685 }
686 brelse(bp1);
687 break;
688
689 default:
690 return D_INVALID_OPERATION;
691 }
692
693 return errcode;
694 }
695
696 setcontroller(int unit)
697 {
698 }
699
700 /* hdstart() is called at spl5 */
701 static void hdstart(void)
702 {
703 struct partition *part_p;
704 int drivecount;
705 register struct buf *bp, *dp;
706
707 if (hh.busy)
708 return;
709
710 for (drivecount = 0; drivecount < NHD; drivecount++) {
711 if (hh.curdrive < (NHD-1))
712 hh.curdrive++;
713 else
714 hh.curdrive = 0;
715 dp = &hdunit[hh.curdrive];
716 if ((bp = dp->b_actf) != NULL)
717 break;
718 }
719 if (drivecount == NHD)
720 return;
721
722 hh.busy = 1;
723 hh.blocktotal = (bp->b_bcount + 511) >> 9;
724
725 assert(hh.blocktotal > 0 || (bp->b_flags&B_RESET));
726
727 part_p = &label[UNIT(bp->b_dev)].d_partitions[PARTITION(bp->b_dev)];
728
729 if (bp->b_flags & B_MD1) {
730 int end = label[UNIT(bp->b_dev)].d_secperunit - 1;
731 hh.physblock = bp->b_blkno;
732 if ((bp->b_blkno + hh.blocktotal) > end)
733 hh.blocktotal = end - bp->b_blkno + 1;
734 } else {
735 hh.physblock = part_p->p_offset + bp->b_blkno;
736 if ((bp->b_blkno + hh.blocktotal ) > part_p->p_size) {
737 hh.blocktotal = part_p->p_size - bp->b_blkno + 1;
738 }
739 }
740 hh.blockcount = 0;
741 hh.rw_addr = (paddr_t)bp->b_un.b_addr;
742 hh.retries = 0;
743
744 start_rw(bp->b_flags & (B_READ | B_RESET));
745
746 }
747
748 hdstrategy(struct buf *bp)
749 {
750 unsigned char unit, partition;
751 struct disklabel *lp;
752 struct partition *part_p;
753 unsigned int opri;
754 long count, total;
755 u_int p_addr, baddr;
756 int i;
757 long size;
758
759 if (!bp->b_bcount)
760 if (bp->b_flags != (bp->b_flags & B_RESET))
761 goto done;
762
763 unit = UNIT((bp->b_dev));
764 lp = &label[unit];
765 partition = PARTITION((bp->b_dev));
766 part_p= &(label[unit].d_partitions[partition]);
767
768 #if 0
769 if (!(bp->b_flags & B_READ) && (part_p->p_flag & V_RONLY)) {
770 printf("hd%d%c: attempt to write read-only partition\n",
771 unit,
772 'a' + partition);
773 bp->b_error = ENXIO;
774 goto bad;
775 }
776 #endif /* 0 */
777
778 /* if request is off the end or trying to write last block on out */
779 size = (bp->b_flags & B_MD1) ? lp->d_secperunit : part_p->p_size;
780 if ((bp->b_blkno > size) ||
781 (bp->b_blkno == size & !(bp->b_flags & B_READ))) {
782 printf("hd%d%c: invalid block %d >= %d\n",
783 unit,
784 'a' + partition,
785 bp->b_blkno,
786 size);
787 bp->b_error = ENXIO;
788 goto bad;
789 }
790 if (bp->b_blkno == size) {
791 /* indicate (read) EOF by setting b_resid to b_bcount on last block */
792 bp->b_resid = bp->b_bcount;
793 goto done;
794 }
795 bp->b_cylin = ((bp->b_flags&B_MD1 ? 0 : part_p->p_offset) + bp->b_blkno)
796 / (lp->d_nsectors * lp->d_ntracks);
797
798 opri = spl5();
799 disksort(&hdunit[unit], bp);
800 if (!hh.busy)
801 hdstart();
802 splx(opri);
803
804 return;
805
806 bad:
807 bp->b_flags |= B_ERROR;
808 done:
809 iodone(bp);
810 return;
811
812 }
813
814 static hderror(struct buf *bp)
815 {
816 int unit = UNIT(bp->b_dev);
817
818 if ((hh.status&0x8000) == 0 || ++hh.retry_count > hdparams[unit].retries) {
819 if(bp) {
820 /************************************************
821 * We have a problem with this block, set the *
822 * error flag, terminate the operation and move *
823 * on to the next request. *
824 * With every hard disk transaction error we set *
825 * the reset requested flag so that the contrlr *
826 * is reset before next operation is started. *
827 * A reset is a relatively long operation, the *
828 * upper level routines are better qualified for *
829 * such an operation than the interrupt service *
830 * routines. *
831 ************************************************/
832 hdunit[hh.curdrive].b_actf = bp->av_forw;
833 bp->b_flags |= B_ERROR;
834 bp->b_resid = 0;
835 biodone(bp);
836 hh.busy = 0;
837 hdstart();
838 }
839 } else {
840 /*
841 * retry the operation using the saved request block
842 */
843 rb[unit] = save_rb[unit];
844 abios_common_start(&rb[unit], params.Logical_id_flags);
845 }
846 }
847
848 /*
849 * The following function is used to get the proper physical
850 * addresses for transfering data.
851 */
852 static u_int hd_max_page(struct buf *bp,
853 u_int baddr,
854 u_int *p_addr,
855 u_int max)
856 {
857 u_int count = ((u_int)baddr) & (I386_PGBYTES - 1);
858 u_int old_addr;
859 u_int new_addr;
860
861
862 if ((*p_addr = pmap_extract(get_pmap(bp), baddr)) == 0)
863 return(0);
864
865 /* if the count is aligned, we can transfer a whole page. */
866 if (count==0)
867 count = I386_PGBYTES;
868 else
869 count = I386_PGBYTES - count;
870
871 /* Now loop through and get the phisical address of each of the
872 following pages. Break on the first non-contiguous page, or when
873 we exceed count.
874 */
875
876 baddr += count;
877 old_addr = *p_addr + count;
878 while ((count <max) &&
879 ((new_addr = pmap_extract(get_pmap(bp), baddr)) != 0) &&
880 (new_addr == old_addr)) {
881 count += I386_PGBYTES;
882 baddr += I386_PGBYTES;
883 old_addr += I386_PGBYTES;
884 }
885
886 return (count > max) ? max : count;
887
888 }
889
890 /*
891 * routine called from timeout code at lower priority
892 * we just call hdintr with the provided parameter.
893 */
894 static void hdtimeout(int vec)
895 {
896 unsigned int s = spl5();
897 hdintr(vec);
898 splx(s);
899 }
900
901 static void start_rw(long read)
902 {
903 unsigned int track, disk_block, xblk;
904 u_int numblocks;
905 unsigned int p_block;
906 int function;
907 paddr_t vert_addr;
908 u_int p_addr;
909 register struct buf *bp, *dp;
910 int i;
911 u_int total;
912 u_char unit;
913
914 dp = &hdunit[unit = hh.curdrive];
915 bp = dp->b_actf;
916
917 restart:
918
919 hh.retry_count = 0; /* start of operation */
920 rb[unit].r_current_req_blck_len = sizeof(struct Gd_request);
921 rb[unit].r_logical_id = hdparams[unit].lid;
922 rb[unit].r_unit = hdparams[unit].unit;
923 rb[unit].r_return_code = ABIOS_UNDEFINED;
924
925 vert_addr = hh.rw_addr + (hh.blockcount * SECSIZE);
926 hh.vert_addr = vert_addr;
927 if ((u_int)vert_addr & 0x1ff) {
928 hh.un_aligned = 1;
929 vert_addr = (paddr_t)u_buf[unit];
930 }
931 p_block = hh.physblock + hh.blockcount;
932
933 numblocks = hd_max_page(bp, vert_addr, &p_addr,
934 ((hh.blocktotal - hh.blockcount)*SECSIZE));
935 numblocks = ((numblocks + 511) >> 9);
936
937 assert(numblocks > 0 || (bp->b_flags&B_RESET));
938
939 hh.phys_addr = p_addr;
940 hh.blockcount += numblocks;
941 hh.numblocks = numblocks;
942
943 switch (read) {
944
945 case B_READ:
946 rb[unit].r_function = ABIOS_READ;
947 function = ABIOS_READ;
948 rb[unit].request_header.Request_Block_Flags = 0;
949 rb[unit].request_header.ELA_Offset = 0;
950 gd_physical_ptr(rb[unit]) = p_addr;
951 gd_logical_ptr(rb[unit]) = 0;
952 gd_blocks_to_read(rb[unit]) = numblocks; /*hh.blocktotal;*/
953 gd_relative_block_address(rb[unit]) = p_block; /*hh.physblock;*/
954 gd_caching_ok(rb[unit]) = GD_DONT_CACHE;
955 GD_SET_RESERVED_ABIOS_READ(rb[unit]);
956 break;
957
958 case B_RESET:
959 rb[unit].r_function = ABIOS_RESET;
960 function = ABIOS_RESET;
961 GD_SET_RESERVED_ABIOS_RESET(rb[unit]);
962 break;
963
964 default:
965 rb[unit].r_function = hd_write_verify ? ABIOS_WRITE_VERIFY : ABIOS_WRITE;
966 function = hd_write_verify ? ABIOS_WRITE_VERIFY : ABIOS_WRITE;
967 rb[unit].request_header.Request_Block_Flags = 0;
968 rb[unit].request_header.ELA_Offset = 0;
969 gd_physical_ptr(rb[unit]) = p_addr;
970 gd_logical_ptr(rb[unit]) = 0;
971 gd_blocks_to_read(rb[unit]) = numblocks; /*hh.blocktotal;*/
972 gd_relative_block_address(rb[unit]) = p_block; /*hh.physblock;*/
973 gd_caching_ok(rb[unit]) = GD_DONT_CACHE;
974 GD_SET_RESERVED_ABIOS_WRITE(rb[unit]);
975 if(hh.un_aligned) {
976 i = 0;
977 total = 0;
978 while (save_addr[unit][i].phys_addr != NULL) {
979 bcopy(phystokv(save_addr[unit][i].phys_addr),
980 (caddr_t)((u_int)u_buf[unit] + total),
981 save_addr[unit][i].count);
982 total += save_addr[unit][i].count;
983 i++;
984 }
985 }
986 break;
987 }
988
989 save_rb[unit] = rb[unit]; /* save in case of retry */
990
991 abios_common_start(&rb[unit], params.Logical_id_flags);
992
993 hh.status = rb[unit].r_return_code;
994
995 switch (hh.status) {
996
997 case ABIOS_STAGE_ON_INT:
998 break;
999
1000 case ABIOS_STAGE_ON_TIME:
1001 timeout(hdtimeout,0,(gd_wait_time(rb[unit])/1000000)*HZ);
1002 break;
1003
1004 case (ABIOS_NOT_MY_INT | ABIOS_STAGE_ON_INT):
1005 /* Eventually we need to chain to the next */
1006 /* interrupt. */
1007 break;
1008
1009 case ABIOS_DONE:
1010 if (hh.blockcount == hh.blocktotal) {
1011 hh.blockcount = 0;
1012 hh.blockcount = 0;
1013 hh.phys_addr = 0;
1014 hh.vert_addr = 0;
1015 hh.numblocks = 0;
1016 dp->b_actf = bp->av_forw;
1017 bp->b_resid = 0;
1018 iodone(bp);
1019 hh.busy = 0;
1020 hdstart();
1021 break;
1022 }
1023 else {
1024 hh.phys_addr = 0;
1025 hh.vert_addr = 0;
1026 hh.numblocks = 0;
1027 goto restart;
1028 }
1029
1030 default:
1031 printf("start_rw: return code [%x]...\n", hh.status);
1032 hd_error_decode(hh.status, "\n");
1033 }
1034
1035 }
1036
1037 #define B_FLAGS_FMT "\2\1READ\2DONE\3ERROR\4BUSY\5PHYS\6XXX\7WANTED\10AGE\11ASYNC\12DELWRI\13TAPE\20CACHE\21INVAL\22LOCKED\23HEAD\24USELESS\25BAD\27RAW\30NOCACHE\31PRIVATE\32WRITEV\33HWRELOC\34WANTFREE"
1038
1039 int hd_bp_all = 0;
1040
1041 static void hd_bp_print(char *msg1, struct buf *bp, char *msg2)
1042 {
1043 printf("%sbp=%x ", msg1 ? msg1 : "", bp);
1044 if (bp) {
1045 printf("b_dev=0x%x b_blkno=0x%x (%d) b_addr=0x%x b_bcount=0x%x b_flags=%b",
1046 bp->b_dev, bp->b_blkno, bp->b_blkno, bp->b_un.b_addr, bp->b_bcount,
1047 bp->b_flags,B_FLAGS_FMT);
1048 if (hd_bp_all) {
1049 printf(" b_forw=0x%x b_back=0x%x av_forw=0x%x av_back=0x%x b_bufsize=%d",
1050 bp->b_forw, bp->b_back, bp->av_forw, bp->av_back,
1051 bp->b_bufsize);
1052 }
1053 }
1054 if (msg2)
1055 printf(msg2);
1056 }
1057
1058 static struct hd_errors { int code; char *msg; } hd_err_codes [] = {
1059 {0x00, "timeout"},
1060 {0x01, "bad-command"},
1061 {0x02, "address-mark-not-found"},
1062 {0x04, "record-not-found"},
1063 {0x05, "reset-failed"},
1064 {0x07, "activity-failed"},
1065 {0x0a, "defective-sector"},
1066 {0x0b, "bad-track"},
1067 {0x0d, "invalid-sector"},
1068 {0x0e, "CAM-detected"},
1069 {0x0f, "DMA-arb-level-bad"},
1070 {0x10, "bad-ecc-error"},
1071 {0x11, "ecc-corrected"},
1072 {0x20, "bad-controller"},
1073 {0x21, "equipment-check"},
1074 {0x40, "bad-seek"},
1075 {0x80, "device-didn't-respond"},
1076 {0xaa, "drive-not-ready"},
1077 {0xbb, "undefined-error"},
1078 {0xcc, "write-fault"},
1079 {0xff, "incomplete-sense"},
1080 {0xc000,"invalid LID"},
1081 {0xc001,"invalid function"},
1082 {0xc003,"invalid unit number"},
1083 {0xc004,"invalid request block length"},
1084 {0xc005,"invalid parameter"}
1085
1086 };
1087
1088 static hd_error_decode(int code, char *msg)
1089 {
1090 int i;
1091 int n = code&0x00ff;
1092
1093 if ((code&0x8000) == 0) {
1094 char *p;
1095 switch(code)
1096 {
1097 case 0:
1098 p = "completed ok";
1099 break;
1100 case 1:
1101 p = "stage on int";
1102 break;
1103 case 2:
1104 p = "stage on time";
1105 break;
1106 case 5:
1107 p = "not my int";
1108 break;
1109 default:
1110 printf("unknown[0x%x]%s", code, msg);
1111 return;
1112 }
1113 printf("%s%s", p, msg);
1114 return;
1115 }
1116 if (code&0x4000) {
1117 printf("PARAMETER ");
1118 n = code;
1119 }
1120 if (code&0x2000)
1121 printf("TIME-OUT ");
1122 if (code&0x1000)
1123 printf("DEVICE ");
1124 if (code&0x100)
1125 printf("RETRYABLE ");
1126 printf("ERROR ");
1127 for (i=0; i<(sizeof hd_err_codes)/(sizeof hd_err_codes[0]); ++i)
1128 if (hd_err_codes[i].code == n)
1129 {
1130 printf("%s%s", hd_err_codes[i].msg, msg);
1131 return;
1132 }
1133 printf("unknown[0x%x]%s", code, msg);
1134 }
1135
1136 static int hdintr(int vec)
1137 {
1138 register struct buf *bp, *dp;
1139 int i;
1140 unsigned long count, total;
1141 unsigned char unit = hh.curdrive;
1142 int rc = 1; /* assume it is ours */
1143
1144 if (!hh.busy && !hh.restoring) {
1145 printf("hdintr: false interrupt continuing . . .\n");
1146 printf("hdintr: hh.busy = %d, hh.restoring = %d\n",
1147 hh.busy, hh.restoring);
1148 printf("hdintr: hh.single_mode = %d, ",hh.single_mode);
1149 printf("hdintr: hh.physblock = %d, ",hh.physblock);
1150 printf("hh.blockcount = %d, ",hh.blockcount);
1151 printf("hh.blocktotal = %d\n",hh.blocktotal);
1152 return;
1153 }
1154
1155 abios_common_interrupt(&rb[unit], params.Logical_id_flags);
1156
1157 hh.status = rb[unit].r_return_code;
1158
1159 dp = &hdunit[hh.curdrive];
1160 bp = dp->b_actf;
1161
1162 switch (hh.status) {
1163
1164 case ABIOS_STAGE_ON_INT:
1165 break;
1166
1167 case ABIOS_STAGE_ON_TIME:
1168 timeout(hdtimeout, 0, (gd_wait_time(rb[unit])/1000000)*HZ);
1169 break;
1170
1171 case ABIOS_NOT_MY_INT:
1172 case (ABIOS_NOT_MY_INT | ABIOS_STAGE_ON_INT):
1173 rc = 0;
1174 break;
1175
1176 case ABIOS_DONE:
1177 if (hh.un_aligned) {
1178 hh.un_aligned = 0;
1179 if (bp->b_flags & B_READ) {
1180 unit = UNIT((bp->b_dev));
1181 i = 0;
1182 total = 0;
1183 while (save_addr[unit][i].phys_addr) {
1184 bcopy(
1185 (caddr_t)((u_int)u_buf[unit] + total),
1186 phystokv(save_addr[unit][i].phys_addr),
1187 save_addr[unit][i].count);
1188 total += save_addr[unit][i].count;
1189 i++;
1190 }
1191 }
1192 }
1193 if (hh.blockcount == hh.blocktotal) {
1194 dp->b_actf = bp->av_forw;
1195 bp->b_resid = 0;
1196 if (hh.retry_count)
1197 printf("retry worked!\n");
1198 biodone(bp);
1199 hh.busy = 0;
1200 hdstart();
1201 }
1202 else {
1203 start_rw(bp->b_flags & (B_READ|B_RESET));
1204 }
1205 break;
1206
1207 default:
1208 printf("[HD Driver] return code [%x]...", hh.status);
1209 hd_error_decode(hh.status,"");
1210 hd_bp_print(" ", bp, "\n");
1211 hderror(bp);
1212 break;
1213
1214 }
1215
1216 return rc;
1217
1218 }
1219
1220 #endif NHD > 0
Cache object: b0c0fe5d11664dd43c86ed2c6587410c
|