mscp_disk.c revision 1.89.8.3 1 /* $NetBSD: mscp_disk.c,v 1.89.8.3 2017/05/17 04:26:14 pgoyette Exp $ */
2 /*
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Chris Torek.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)uda.c 7.32 (Berkeley) 2/13/91
34 */
35
36 /*
37 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Chris Torek.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 * @(#)uda.c 7.32 (Berkeley) 2/13/91
71 */
72
73 /*
74 * RA disk device driver
75 * RX MSCP floppy disk device driver
76 * RRD MSCP CD device driver
77 */
78
79 /*
80 * TODO
81 * write bad block forwarding code
82 */
83
84 #include <sys/cdefs.h>
85 __KERNEL_RCSID(0, "$NetBSD: mscp_disk.c,v 1.89.8.3 2017/05/17 04:26:14 pgoyette Exp $");
86
87 #include <sys/param.h>
88 #include <sys/buf.h>
89 #include <sys/bufq.h>
90 #include <sys/device.h>
91 #include <sys/disk.h>
92 #include <sys/disklabel.h>
93 #include <sys/ioctl.h>
94 #include <sys/stat.h>
95 #include <sys/fcntl.h>
96 #include <sys/reboot.h>
97 #include <sys/proc.h>
98 #include <sys/systm.h>
99 #include <sys/conf.h>
100
101 #include <ufs/ufs/dinode.h>
102 #include <ufs/ffs/fs.h>
103
104 #include <sys/bus.h>
105 #include <sys/cpu.h>
106
107 #include <dev/mscp/mscp.h>
108 #include <dev/mscp/mscpreg.h>
109 #include <dev/mscp/mscpvar.h>
110
111 #include "locators.h"
112 #include "ioconf.h"
113 #include "ra.h"
114
115 /*
116 * Drive status, per drive
117 */
118 struct ra_softc {
119 device_t ra_dev; /* Autoconf struct */
120 struct disk ra_disk;
121 int ra_state; /* open/closed state */
122 u_long ra_mediaid; /* media id */
123 int ra_hwunit; /* Hardware unit number */
124 int ra_havelabel; /* true if we have a label */
125 int ra_wlabel; /* label sector is currently writable */
126 };
127
128 #define rx_softc ra_softc
129 #define racd_softc ra_softc
130
131 void raattach(device_t, device_t, void *);
132 int rx_putonline(struct rx_softc *);
133 void rrmakelabel(struct disklabel *, long);
134 int ra_putonline(dev_t, struct ra_softc *);
135 static inline struct ra_softc *mscp_device_lookup(dev_t);
136
137 #if NRA
138
139 int ramatch(device_t, cfdata_t, void *);
140
141 CFATTACH_DECL_NEW(ra, sizeof(struct ra_softc),
142 ramatch, raattach, NULL, NULL);
143
144 #endif /* NRA */
145
146 #if NRA || NRACD || NRX
147
148 dev_type_open(raopen);
149 dev_type_close(raclose);
150 dev_type_read(raread);
151 dev_type_write(rawrite);
152 dev_type_ioctl(raioctl);
153 dev_type_strategy(rastrategy);
154 dev_type_dump(radump);
155 dev_type_size(rasize);
156
157 #if NRA
158
159 const struct bdevsw ra_bdevsw = {
160 .d_open = raopen,
161 .d_close = raclose,
162 .d_strategy = rastrategy,
163 .d_ioctl = raioctl,
164 .d_dump = radump,
165 .d_psize = rasize,
166 .d_discard = nodiscard,
167 .d_flag = D_DISK
168 };
169
170 const struct cdevsw ra_cdevsw = {
171 .d_open = raopen,
172 .d_close = raclose,
173 .d_read = raread,
174 .d_write = rawrite,
175 .d_ioctl = raioctl,
176 .d_stop = nostop,
177 .d_tty = notty,
178 .d_poll = nopoll,
179 .d_mmap = nommap,
180 .d_kqfilter = nokqfilter,
181 .d_discard = nodiscard,
182 .d_flag = D_DISK
183 };
184
185 static struct dkdriver radkdriver = {
186 .d_strategy = rastrategy,
187 .d_minphys = minphys
188 };
189
190 /*
191 * More driver definitions, for generic MSCP code.
192 */
193
194 int
195 ramatch(device_t parent, cfdata_t cf, void *aux)
196 {
197 struct drive_attach_args *da = aux;
198 struct mscp *mp = da->da_mp;
199
200 if ((da->da_typ & MSCPBUS_DISK) == 0)
201 return 0;
202 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
203 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
204 return 0;
205 /*
206 * Check if this disk is a floppy (RX) or cd (RRD)
207 * Seems to be a safe way to test it per Chris Torek.
208 */
209 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
210 return 0;
211 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
212 return 0;
213 return 1;
214 }
215
216 #endif /* NRA */
217
218 /*
219 * Open a drive.
220 */
221 /*ARGSUSED*/
222 int
223 raopen(dev_t dev, int flag, int fmt, struct lwp *l)
224 {
225 struct ra_softc *ra = mscp_device_lookup(dev);
226 int error, part, mask;
227 /*
228 * Make sure this is a reasonable open request.
229 */
230 if (!ra)
231 return ENXIO;
232
233 part = DISKPART(dev);
234
235 mutex_enter(&ra->ra_disk.dk_openlock);
236
237 /*
238 * If there are wedges, and this is not RAW_PART, then we
239 * need to fail.
240 */
241 if (ra->ra_disk.dk_nwedges != 0 && part != RAW_PART) {
242 error = EBUSY;
243 goto bad1;
244 }
245
246 /*
247 * If this is the first open; we must first try to put
248 * the disk online (and read the label).
249 */
250 if (ra->ra_state == DK_CLOSED) {
251 if (ra_putonline(dev, ra) == MSCP_FAILED) {
252 error = ENXIO;
253 goto bad1;
254 }
255 }
256
257 /* If the disk has no label; allow writing everywhere */
258 if (ra->ra_havelabel == 0)
259 ra->ra_wlabel = 1;
260
261 if (part >= ra->ra_disk.dk_label->d_npartitions) {
262 error = ENXIO;
263 goto bad1;
264 }
265
266 /*
267 * Wait for the state to settle
268 */
269 #if notyet
270 while (ra->ra_state != DK_OPEN)
271 if ((error = tsleep((void *)ra, (PZERO + 1) | PCATCH,
272 devopn, 0))) {
273 splx(s);
274 goto bad2;
275 }
276 #endif
277
278 mask = 1 << part;
279
280 switch (fmt) {
281 case S_IFCHR:
282 ra->ra_disk.dk_copenmask |= mask;
283 break;
284 case S_IFBLK:
285 ra->ra_disk.dk_bopenmask |= mask;
286 break;
287 }
288 ra->ra_disk.dk_openmask |= mask;
289 error = 0;
290 bad1:
291 mutex_exit(&ra->ra_disk.dk_openlock);
292 bad2:
293 device_release(ra->ra_dev);
294 return (error);
295 }
296
297 /* ARGSUSED */
298 int
299 raclose(dev_t dev, int flags, int fmt, struct lwp *l)
300 {
301 struct ra_softc *ra = mscp_device_lookup(dev);
302 int mask = (1 << DISKPART(dev));
303
304 mutex_enter(&ra->ra_disk.dk_openlock);
305
306 switch (fmt) {
307 case S_IFCHR:
308 ra->ra_disk.dk_copenmask &= ~mask;
309 break;
310 case S_IFBLK:
311 ra->ra_disk.dk_bopenmask &= ~mask;
312 break;
313 }
314 ra->ra_disk.dk_openmask =
315 ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask;
316
317 /*
318 * Should wait for I/O to complete on this partition even if
319 * others are open, but wait for work on blkflush().
320 */
321 #if notyet
322 if (ra->ra_openpart == 0) {
323 s = spluba();
324 while (bufq_peek(udautab[unit]) != NULL)
325 (void) tsleep(&udautab[unit], PZERO - 1,
326 "raclose", 0);
327 splx(s);
328 ra->ra_state = DK_CLOSED;
329 ra->ra_wlabel = 0;
330 }
331 #endif
332 mutex_exit(&ra->ra_disk.dk_openlock);
333 device_release(ra->ra_dev);
334 return (0);
335 }
336
337 /*
338 * Queue a transfer request, and if possible, hand it to the controller.
339 */
340 void
341 rastrategy(struct buf *bp)
342 {
343 struct ra_softc *ra = mscp_device_lookup(bp->b_dev);
344 int b;
345
346 /*
347 * Make sure this is a reasonable drive to use.
348 */
349 if (ra == NULL) {
350 bp->b_error = ENXIO;
351 goto done1;
352 }
353 /*
354 * If drive is open `raw' or reading label, let it at it.
355 */
356 if (ra->ra_state == DK_RDLABEL) {
357 /* Make some statistics... /bqt */
358 b = splbio();
359 disk_busy(&ra->ra_disk);
360 splx(b);
361 mscp_strategy(bp, device_parent(ra->ra_dev));
362 device_release(ra->ra_dev);
363 return;
364 }
365
366 /* If disk is not online, try to put it online */
367 if (ra->ra_state == DK_CLOSED)
368 if (ra_putonline(bp->b_dev, ra) == MSCP_FAILED) {
369 bp->b_error = EIO;
370 goto done;
371 }
372
373 /*
374 * Determine the size of the transfer, and make sure it is
375 * within the boundaries of the partition.
376 */
377 if (bounds_check_with_label(&ra->ra_disk, bp, ra->ra_wlabel) <= 0)
378 goto done;
379
380 /* Make some statistics... /bqt */
381 b = splbio();
382 disk_busy(&ra->ra_disk);
383 splx(b);
384 mscp_strategy(bp, device_parent(ra->ra_dev));
385 device_release(ra->ra_dev);
386 return;
387
388 done:
389 device_release(ra->ra_dev);
390 done1:
391 biodone(bp);
392 }
393
394 int
395 raread(dev_t dev, struct uio *uio, int flags)
396 {
397
398 return (physio(rastrategy, NULL, dev, B_READ, minphys, uio));
399 }
400
401 int
402 rawrite(dev_t dev, struct uio *uio, int flags)
403 {
404
405 return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio));
406 }
407
408 /*
409 * I/O controls.
410 */
411 int
412 raioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
413 {
414 struct disklabel *lp, *tp;
415 struct ra_softc *ra = mscp_device_lookup(dev);
416 int error;
417 #ifdef __HAVE_OLD_DISKLABEL
418 struct disklabel newlabel;
419 #endif
420
421 lp = ra->ra_disk.dk_label;
422
423 error = disk_ioctl(&ra->ra_disk, dev, cmd, data, flag, l);
424 if (error != EPASSTHROUGH) {
425 device_release(ra->ra_dev);
426 return error;
427 } else
428 error = 0;
429
430 switch (cmd) {
431 case DIOCWDINFO:
432 case DIOCSDINFO:
433 #ifdef __HAVE_OLD_DISKLABEL
434 case ODIOCWDINFO:
435 case ODIOCSDINFO:
436 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
437 memset(&newlabel, 0, sizeof newlabel);
438 memcpy(&newlabel, data, sizeof (struct olddisklabel));
439 tp = &newlabel;
440 } else
441 #endif
442 tp = (struct disklabel *)data;
443
444 if ((flag & FWRITE) == 0)
445 error = EBADF;
446 else {
447 mutex_enter(&ra->ra_disk.dk_openlock);
448 error = setdisklabel(lp, tp, 0, 0);
449 if ((error == 0) && (cmd == DIOCWDINFO
450 #ifdef __HAVE_OLD_DISKLABEL
451 || cmd == ODIOCWDINFO
452 #endif
453 )) {
454 ra->ra_wlabel = 1;
455 error = writedisklabel(dev, rastrategy, lp,0);
456 ra->ra_wlabel = 0;
457 }
458 mutex_exit(&ra->ra_disk.dk_openlock);
459 }
460 break;
461
462 case DIOCWLABEL:
463 if ((flag & FWRITE) == 0)
464 error = EBADF;
465 else
466 ra->ra_wlabel = 1;
467 break;
468
469 case DIOCGDEFLABEL:
470 #ifdef __HAVE_OLD_DISKLABEL
471 case ODIOCGDEFLABEL:
472 if (cmd == ODIOCGDEFLABEL)
473 tp = &newlabel;
474 else
475 #endif
476 tp = (struct disklabel *)data;
477 memset(tp, 0, sizeof(struct disklabel));
478 tp->d_secsize = lp->d_secsize;
479 tp->d_nsectors = lp->d_nsectors;
480 tp->d_ntracks = lp->d_ntracks;
481 tp->d_ncylinders = lp->d_ncylinders;
482 tp->d_secpercyl = lp->d_secpercyl;
483 tp->d_secperunit = lp->d_secperunit;
484 tp->d_type = DKTYPE_MSCP;
485 tp->d_rpm = 3600;
486 rrmakelabel(tp, ra->ra_mediaid);
487 #ifdef __HAVE_OLD_DISKLABEL
488 if (cmd == ODIOCGDEFLABEL) {
489 if (tp->d_npartitions > OLDMAXPARTITIONS)
490 return ENOTTY;
491 memcpy(data, tp, sizeof (struct olddisklabel));
492 }
493 #endif
494 break;
495
496 default:
497 error = ENOTTY;
498 break;
499 }
500 device_release(ra->ra_dev);
501 return (error);
502 }
503
504 int
505 radump(dev_t dev, daddr_t blkno, void *va, size_t size)
506 {
507 return ENXIO;
508 }
509
510 /*
511 * Return the size of a partition, if known, or -1 if not.
512 */
513 int
514 rasize(dev_t dev)
515 {
516 int rv;
517 struct ra_softc *ra = mscp_device_lookup(dev);
518
519 if (!ra)
520 return -1;
521
522 if (ra->ra_state == DK_CLOSED)
523 if (ra_putonline(dev, ra) == MSCP_FAILED) {
524 device_release(ra->ra_dev);
525 return -1;
526 }
527
528 rv = ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
529 (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
530 device_release(ra->ra_dev);
531 return rv;
532 }
533
534 #endif /* NRA || NRACD || NRX */
535
536 #if NRX
537
538 int rxmatch(device_t, cfdata_t, void *);
539
540 CFATTACH_DECL_NEW(rx, sizeof(struct rx_softc),
541 rxmatch, raattach, NULL, NULL);
542
543 dev_type_open(rxopen);
544 dev_type_read(rxread);
545 dev_type_write(rxwrite);
546 dev_type_ioctl(rxioctl);
547 dev_type_strategy(rxstrategy);
548 dev_type_dump(radump);
549 dev_type_size(rxsize);
550
551 const struct bdevsw rx_bdevsw = {
552 .d_open = rxopen,
553 .d_close = nullclose,
554 .d_strategy = rxstrategy,
555 .d_ioctl = rxioctl,
556 .d_dump = radump,
557 .d_psize = rxsize,
558 .d_discard = nodiscard,
559 .d_flag = D_DISK
560 };
561
562 const struct cdevsw rx_cdevsw = {
563 .d_open = rxopen,
564 .d_close = nullclose,
565 .d_read = rxread,
566 .d_write = rxwrite,
567 .d_ioctl = rxioctl,
568 .d_stop = nostop,
569 .d_tty = notty,
570 .d_poll = nopoll,
571 .d_mmap = nommap,
572 .d_kqfilter = nokqfilter,
573 .d_discard = nodiscard,
574 .d_flag = D_DISK
575 };
576
577 static struct dkdriver rxdkdriver = {
578 rxstrategy, minphys
579 };
580
581 /*
582 * More driver definitions, for generic MSCP code.
583 */
584
585 int
586 rxmatch(device_t parent, cfdata_t cf, void *aux)
587 {
588 struct drive_attach_args *da = aux;
589 struct mscp *mp = da->da_mp;
590
591 if ((da->da_typ & MSCPBUS_DISK) == 0)
592 return 0;
593 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
594 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
595 return 0;
596 /*
597 * Check if this disk is a floppy (RX)
598 * Seems to be a safe way to test it per Chris Torek.
599 */
600 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
601 return 1;
602 return 0;
603 }
604
605 #endif /* NRX */
606
607 #if NRACD
608
609 /* Use almost all ra* routines for racd */
610
611 int racdmatch(device_t, cfdata_t, void *);
612
613 CFATTACH_DECL_NEW(racd, sizeof(struct racd_softc),
614 racdmatch, raattach, NULL, NULL);
615
616 dev_type_open(raopen);
617 dev_type_read(raread);
618 dev_type_write(rawrite);
619 dev_type_ioctl(raioctl);
620 dev_type_strategy(rastrategy);
621 dev_type_dump(radump);
622 dev_type_size(rasize);
623
624 const struct bdevsw racd_bdevsw = {
625 .d_open = raopen,
626 .d_close = nullclose,
627 .d_strategy = rastrategy,
628 .d_ioctl = raioctl,
629 .d_dump = radump,
630 .d_psize = rasize,
631 .d_discard = nodiscard,
632 .d_flag = D_DISK
633 };
634
635 const struct cdevsw racd_cdevsw = {
636 .d_open = raopen,
637 .d_close = nullclose,
638 .d_read = raread,
639 .d_write = rawrite,
640 .d_ioctl = raioctl,
641 .d_stop = nostop,
642 .d_tty = notty,
643 .d_poll = nopoll,
644 .d_mmap = nommap,
645 .d_kqfilter = nokqfilter,
646 .d_discard = nodiscard,
647 .d_flag = D_DISK
648 };
649
650 static struct dkdriver racddkdriver = {
651 rastrategy, minphys
652 };
653
654 /*
655 * More driver definitions, for generic MSCP code.
656 */
657
658 int
659 racdmatch(device_t parent, cfdata_t cf, void *aux)
660 {
661 struct drive_attach_args *da = aux;
662 struct mscp *mp = da->da_mp;
663
664 if ((da->da_typ & MSCPBUS_DISK) == 0)
665 return 0;
666 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
667 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
668 return 0;
669 /*
670 * Check if this disk is a CD (RRD)
671 */
672 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
673 return 1;
674 return 0;
675 }
676
677 #endif /* NRACD */
678
679 /*
680 * The attach routine only checks and prints drive type.
681 * Bringing the disk online is done when the disk is accessed
682 * the first time.
683 */
684 void
685 raattach(device_t parent, device_t self, void *aux)
686 {
687 struct rx_softc *rx = device_private(self);
688 struct drive_attach_args *da = aux;
689 struct mscp *mp = da->da_mp;
690 struct mscp_softc *mi = device_private(parent);
691 struct disklabel *dl;
692
693 rx->ra_dev = self;
694 rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
695 rx->ra_state = DK_CLOSED;
696 rx->ra_hwunit = mp->mscp_unit;
697 mi->mi_dp[mp->mscp_unit] = self;
698
699 #if NRX
700 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
701 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
702 &rxdkdriver);
703 #endif
704 #if NRACD
705 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
706 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
707 &racddkdriver);
708 #endif
709 #if NRA
710 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@' &&
711 MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'R' - '@')
712 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
713 &radkdriver);
714 #endif
715 disk_attach(&rx->ra_disk);
716
717 /* Fill in what we know. The actual size is gotten later */
718 dl = rx->ra_disk.dk_label;
719
720 dl->d_secsize = DEV_BSIZE;
721 dl->d_nsectors = mp->mscp_guse.guse_nspt;
722 dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
723 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
724 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
725 #ifdef DEBUG
726 printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
727 device_xname(self), mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
728 mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
729 mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
730 #endif
731 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@') {
732 /*
733 * XXX We should try to discover wedges here, but
734 * XXX that would mean being able to do I/O. Should
735 * XXX use config_defer() here.
736 */
737 }
738 }
739
740 /*
741 * Initialize drive geometry data from disklabel
742 */
743 static void
744 ra_set_geometry(struct ra_softc *ra)
745 {
746 struct disklabel *dl;
747 struct disk_geom *dg;
748
749 dl = ra->ra_disk.dk_label;
750 dg = &ra->ra_disk.dk_geom;
751
752 memset(dg, 0, sizeof(*dg));
753 dg->dg_secsize = dl->d_secsize;
754 dg->dg_nsectors = dl->d_nsectors;
755 dg->dg_ntracks = dl->d_ntracks;
756
757 dg->dg_ncylinders = dl->d_ncylinders;
758 dg->dg_secperunit = dl->d_secperunit;
759
760 disk_set_info(ra->ra_dev, &ra->ra_disk, NULL);
761 }
762
763 /*
764 * (Try to) put the drive online. This is done the first time the
765 * drive is opened, or if it har fallen offline.
766 */
767 int
768 rx_putonline(struct rx_softc *rx)
769 {
770 struct mscp *mp;
771 struct mscp_softc *mi = device_private(device_parent(rx->ra_dev));
772
773 rx->ra_state = DK_CLOSED;
774 mp = mscp_getcp(mi, MSCP_WAIT);
775 mp->mscp_opcode = M_OP_ONLINE;
776 mp->mscp_unit = rx->ra_hwunit;
777 mp->mscp_cmdref = 1;
778 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
779
780 /* Poll away */
781 bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
782 if (tsleep(&rx->ra_state, PRIBIO, "rxonline", 100*100))
783 rx->ra_state = DK_CLOSED;
784
785 if (rx->ra_state == DK_CLOSED)
786 return MSCP_FAILED;
787
788 return MSCP_DONE;
789 }
790
791 #if NRX
792
793 /*
794 * Open a drive.
795 */
796 /*ARGSUSED*/
797 int
798 rxopen(dev_t dev, int flag, int fmt, struct lwp *l)
799 {
800 struct rx_softc *rx;
801 int unit;
802
803 /*
804 * Make sure this is a reasonable open request.
805 */
806 unit = DISKUNIT(dev);
807 rx = device_lookup_private(&rx_cd, unit);
808 if (!rx)
809 return ENXIO;
810
811 /*
812 * If this is the first open; we must first try to put
813 * the disk online (and read the label).
814 */
815 if (rx->ra_state == DK_CLOSED)
816 if (rx_putonline(rx) == MSCP_FAILED)
817 return ENXIO;
818
819 return 0;
820 }
821
822 /*
823 * Queue a transfer request, and if possible, hand it to the controller.
824 *
825 * This routine is broken into two so that the internal version
826 * udastrat1() can be called by the (nonexistent, as yet) bad block
827 * revectoring routine.
828 */
829 void
830 rxstrategy(struct buf *bp)
831 {
832 int unit;
833 struct rx_softc *rx;
834 int b;
835
836 /*
837 * Make sure this is a reasonable drive to use.
838 */
839 unit = DISKUNIT(bp->b_dev);
840 if ((rx = device_lookup_private(&rx_cd, unit)) == NULL) {
841 bp->b_error = ENXIO;
842 goto done;
843 }
844
845 /* If disk is not online, try to put it online */
846 if (rx->ra_state == DK_CLOSED)
847 if (rx_putonline(rx) == MSCP_FAILED) {
848 bp->b_error = EIO;
849 goto done;
850 }
851
852 /*
853 * Determine the size of the transfer, and make sure it is
854 * within the boundaries of the partition.
855 */
856 if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
857 bp->b_resid = bp->b_bcount;
858 goto done;
859 }
860
861 /* Make some statistics... /bqt */
862 b = splbio();
863 disk_busy(&rx->ra_disk);
864 splx(b);
865 mscp_strategy(bp, device_parent(rx->ra_dev));
866 return;
867
868 done:
869 biodone(bp);
870 }
871
872 int
873 rxread(dev_t dev, struct uio *uio, int flag)
874 {
875
876 return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
877 }
878
879 int
880 rxwrite(dev_t dev, struct uio *uio, int flag)
881 {
882
883 return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
884 }
885
886 /*
887 * I/O controls.
888 */
889 int
890 rxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
891 {
892 int unit = DISKUNIT(dev);
893 struct rx_softc *rx = device_lookup_private(&rx_cd, unit);
894 int error;
895
896 error = disk_ioctl(&rx->ra_disk, dev, cmd, data, flag, l);
897 if (error != EPASSTHROUGH)
898 return error;
899 else
900 error = 0;
901
902 switch (cmd) {
903 case DIOCWDINFO:
904 case DIOCSDINFO:
905 case DIOCWLABEL:
906 break;
907
908 default:
909 error = ENOTTY;
910 break;
911 }
912 return (error);
913 }
914
915 int
916 rxsize(dev_t dev)
917 {
918
919 return -1;
920 }
921
922 #endif /* NRX */
923
924 void rrdgram(device_t, struct mscp *, struct mscp_softc *);
925 void rriodone(device_t, struct buf *);
926 int rronline(device_t, struct mscp *);
927 int rrgotstatus(device_t, struct mscp *);
928 void rrreplace(device_t, struct mscp *);
929 int rrioerror(device_t, struct mscp *, struct buf *);
930 void rrfillin(struct buf *, struct mscp *);
931 void rrbb(device_t, struct mscp *, struct buf *);
932
933
934 struct mscp_device ra_device = {
935 rrdgram,
936 rriodone,
937 rronline,
938 rrgotstatus,
939 rrreplace,
940 rrioerror,
941 rrbb,
942 rrfillin,
943 };
944
945 /*
946 * Handle an error datagram.
947 * This can come from an unconfigured drive as well.
948 */
949 void
950 rrdgram(device_t usc, struct mscp *mp, struct mscp_softc *mi)
951 {
952 if (mscp_decodeerror(usc == NULL?"unconf disk" : device_xname(usc), mp, mi))
953 return;
954 /*
955 * SDI status information bytes 10 and 11 are the microprocessor
956 * error code and front panel code respectively. These vary per
957 * drive type and are printed purely for field service information.
958 */
959 if (mp->mscp_format == M_FM_SDI)
960 printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
961 mp->mscp_erd.erd_sdistat[10],
962 mp->mscp_erd.erd_sdistat[11]);
963 }
964
965
966 void
967 rriodone(device_t usc, struct buf *bp)
968 {
969 struct ra_softc *ra = device_private(usc);
970
971 disk_unbusy(&ra->ra_disk, bp->b_bcount, (bp->b_flags & B_READ));
972
973 biodone(bp);
974 }
975
976 /*
977 * A drive came on line. Check its type and size. Return DONE if
978 * we think the drive is truly on line. In any case, awaken anyone
979 * sleeping on the drive on-line-ness.
980 */
981 int
982 rronline(device_t usc, struct mscp *mp)
983 {
984 struct ra_softc *ra = device_private(usc);
985 struct disklabel *dl;
986
987 wakeup((void *)&ra->ra_state);
988 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
989 aprint_error_dev(usc, "attempt to bring on line failed: ");
990 mscp_printevent(mp);
991 return (MSCP_FAILED);
992 }
993
994 ra->ra_state = DK_OPEN;
995
996 dl = ra->ra_disk.dk_label;
997 dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
998
999 if (dl->d_secpercyl) {
1000 dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
1001 dl->d_type = DKTYPE_MSCP;
1002 dl->d_rpm = 3600;
1003 } else {
1004 dl->d_type = DKTYPE_FLOPPY;
1005 dl->d_rpm = 300;
1006 }
1007 rrmakelabel(dl, ra->ra_mediaid);
1008 ra_set_geometry(ra);
1009
1010 return (MSCP_DONE);
1011 }
1012
1013 void
1014 rrmakelabel(struct disklabel *dl, long type)
1015 {
1016 int n, p = 0;
1017
1018 dl->d_bbsize = BBSIZE;
1019 dl->d_sbsize = SBLOCKSIZE;
1020
1021 /* Create the disk name for disklabel. Phew... */
1022 dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
1023 dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
1024 if (MSCP_MID_ECH(0, type))
1025 dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
1026 n = MSCP_MID_NUM(type);
1027 if (n > 99) {
1028 dl->d_typename[p++] = '1';
1029 n -= 100;
1030 }
1031 if (n > 9) {
1032 dl->d_typename[p++] = (n / 10) + '0';
1033 n %= 10;
1034 }
1035 dl->d_typename[p++] = n + '0';
1036 dl->d_typename[p] = 0;
1037 dl->d_npartitions = MAXPARTITIONS;
1038 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
1039 dl->d_secperunit;
1040 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
1041 dl->d_interleave = dl->d_headswitch = 1;
1042 dl->d_magic = dl->d_magic2 = DISKMAGIC;
1043 dl->d_checksum = dkcksum(dl);
1044 }
1045
1046 /*
1047 * We got some (configured) unit's status. Return DONE if it succeeded.
1048 */
1049 int
1050 rrgotstatus(device_t usc, struct mscp *mp)
1051 {
1052 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
1053 aprint_error_dev(usc, "attempt to get status failed: ");
1054 mscp_printevent(mp);
1055 return (MSCP_FAILED);
1056 }
1057 /* record for (future) bad block forwarding and whatever else */
1058 #ifdef notyet
1059 uda_rasave(ui->ui_unit, mp, 1);
1060 #endif
1061 return (MSCP_DONE);
1062 }
1063
1064 /*
1065 * A replace operation finished.
1066 */
1067 /*ARGSUSED*/
1068 void
1069 rrreplace(device_t usc, struct mscp *mp)
1070 {
1071
1072 panic("udareplace");
1073 }
1074
1075 /*
1076 * A transfer failed. We get a chance to fix or restart it.
1077 * Need to write the bad block forwaring code first....
1078 */
1079 /*ARGSUSED*/
1080 int
1081 rrioerror(device_t usc, struct mscp *mp, struct buf *bp)
1082 {
1083 struct ra_softc *ra = device_private(usc);
1084 int code = mp->mscp_event;
1085
1086 switch (code & M_ST_MASK) {
1087 /* The unit has fallen offline. Try to figure out why. */
1088 case M_ST_OFFLINE:
1089 bp->b_error = EIO;
1090 ra->ra_state = DK_CLOSED;
1091 if (code & M_OFFLINE_UNMOUNTED)
1092 aprint_error_dev(usc, "not mounted/spun down\n");
1093 if (code & M_OFFLINE_DUPLICATE)
1094 aprint_error_dev(usc, "duplicate unit number!!!\n");
1095 return MSCP_DONE;
1096
1097 case M_ST_AVAILABLE:
1098 ra->ra_state = DK_CLOSED; /* Force another online */
1099 return MSCP_DONE;
1100
1101 default:
1102 printf("%s:", device_xname(usc));
1103 break;
1104 }
1105 return (MSCP_FAILED);
1106 }
1107
1108 /*
1109 * Fill in disk addresses in a mscp packet waiting for transfer.
1110 */
1111 void
1112 rrfillin(struct buf *bp, struct mscp *mp)
1113 {
1114 struct ra_softc *ra;
1115 struct disklabel *lp;
1116 int part = DISKPART(bp->b_dev);
1117
1118 ra = mscp_device_lookup(bp->b_dev);
1119 lp = ra->ra_disk.dk_label;
1120
1121 mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
1122 mp->mscp_unit = ra->ra_hwunit;
1123 mp->mscp_seq.seq_bytecount = bp->b_bcount;
1124 device_release(ra->ra_dev);
1125 }
1126
1127 /*
1128 * A bad block related operation finished.
1129 */
1130 /*ARGSUSED*/
1131 void
1132 rrbb(device_t usc, struct mscp *mp, struct buf *bp)
1133 {
1134
1135 panic("udabb");
1136 }
1137
1138 /*
1139 * (Try to) put the drive online. This is done the first time the
1140 * drive is opened, or if it has fallen offline.
1141 */
1142 int
1143 ra_putonline(dev_t dev, struct ra_softc *ra)
1144 {
1145 struct disklabel *dl;
1146 const char *msg;
1147 #if NRACD
1148 const struct cdevsw *cdev;
1149 #endif
1150
1151 if (rx_putonline(ra) != MSCP_DONE)
1152 return MSCP_FAILED;
1153
1154 dl = ra->ra_disk.dk_label;
1155
1156 ra->ra_state = DK_RDLABEL;
1157 printf("%s", device_xname(ra->ra_dev));
1158 if ((msg = readdisklabel(
1159 MAKEDISKDEV(major(dev), device_unit(ra->ra_dev), RAW_PART),
1160 rastrategy, dl, NULL)) == NULL) {
1161 ra->ra_havelabel = 1;
1162 ra->ra_state = DK_OPEN;
1163 } else {
1164 #if NRACD
1165 cdev = cdevsw_lookup_acquire(dev);
1166 if (cdev == &racd_cdevsw) {
1167 dl->d_partitions[0].p_offset = 0;
1168 dl->d_partitions[0].p_size = dl->d_secperunit;
1169 dl->d_partitions[0].p_fstype = FS_ISO9660;
1170 } else
1171 printf(": %s", msg);
1172 if (cdev != NULL)
1173 cdevsw_release(cdev);
1174 #else
1175 printf(": %s", msg);
1176 #endif /* NRACD */
1177 }
1178
1179 printf(": size %d sectors\n", dl->d_secperunit);
1180
1181 return MSCP_DONE;
1182 }
1183
1184 static inline struct ra_softc *
1185 mscp_device_lookup(dev_t dev)
1186 {
1187 const struct dev_cdevsw;
1188 struct ra_softc *ra;
1189 int unit;
1190
1191 unit = DISKUNIT(dev);
1192 ra = NULL;
1193 #if NRA
1194 if (( dev_cdevsw = cdevsw_lookup_acquire(dev)) == &ra_cdevsw) {
1195 ra = device_lookup_private(&ra_cd, unit);
1196 cdevsw_release(dev_cdevsw);
1197 return ra;
1198 } else
1199 cdevsw_release(dev_cdevsw);
1200 #endif
1201 #if NRACD
1202 if ((dev_cdevsw = cdevsw_lookup(dev)) == &racd_cdevsw) {
1203 ra = device_lookup_private(&racd_cd, unit);
1204 cdevsw_release(dev_cdevsw);
1205 return ra;
1206 } else
1207 cdevsw_release(dev_cdevsw);
1208 #endif
1209 #if NRX
1210 if (cdevsw_lookup(dev) == &rx_cdevsw)
1211 ra = device_lookup_private(&rx_cd, unit);
1212 cdevsw_release(dev_cdevsw);
1213 return ra;
1214 else
1215 cdevsw_release(dev_cdevsw);
1216 #endif
1217 panic("mscp_device_lookup: unexpected major %"PRIu32" unit %u",
1218 major(dev), unit);
1219 }
1220
1221 static void
1222 mscp_devsw_release(struct ra_softc *sc)
1223 {
1224
1225 device_release(sc->ra_dev);
1226 }
1227