mscp_disk.c revision 1.80 1 /* $NetBSD: mscp_disk.c,v 1.80 2014/07/25 08:02:19 dholland 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.80 2014/07/25 08:02:19 dholland 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_flag = D_DISK
182 };
183
184 static struct dkdriver radkdriver = {
185 rastrategy, minphys
186 };
187
188 /*
189 * More driver definitions, for generic MSCP code.
190 */
191
192 int
193 ramatch(device_t parent, cfdata_t cf, void *aux)
194 {
195 struct drive_attach_args *da = aux;
196 struct mscp *mp = da->da_mp;
197
198 if ((da->da_typ & MSCPBUS_DISK) == 0)
199 return 0;
200 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
201 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
202 return 0;
203 /*
204 * Check if this disk is a floppy (RX) or cd (RRD)
205 * Seems to be a safe way to test it per Chris Torek.
206 */
207 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
208 return 0;
209 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
210 return 0;
211 return 1;
212 }
213
214 #endif /* NRA */
215
216 /*
217 * Open a drive.
218 */
219 /*ARGSUSED*/
220 int
221 raopen(dev_t dev, int flag, int fmt, struct lwp *l)
222 {
223 struct ra_softc *ra = mscp_device_lookup(dev);
224 int error, part, mask;
225 /*
226 * Make sure this is a reasonable open request.
227 */
228 if (!ra)
229 return ENXIO;
230
231 part = DISKPART(dev);
232
233 mutex_enter(&ra->ra_disk.dk_openlock);
234
235 /*
236 * If there are wedges, and this is not RAW_PART, then we
237 * need to fail.
238 */
239 if (ra->ra_disk.dk_nwedges != 0 && part != RAW_PART) {
240 error = EBUSY;
241 goto bad1;
242 }
243
244 /*
245 * If this is the first open; we must first try to put
246 * the disk online (and read the label).
247 */
248 if (ra->ra_state == DK_CLOSED) {
249 if (ra_putonline(dev, ra) == MSCP_FAILED) {
250 error = ENXIO;
251 goto bad1;
252 }
253 }
254
255 /* If the disk has no label; allow writing everywhere */
256 if (ra->ra_havelabel == 0)
257 ra->ra_wlabel = 1;
258
259 if (part >= ra->ra_disk.dk_label->d_npartitions) {
260 error = ENXIO;
261 goto bad1;
262 }
263
264 /*
265 * Wait for the state to settle
266 */
267 #if notyet
268 while (ra->ra_state != DK_OPEN)
269 if ((error = tsleep((void *)ra, (PZERO + 1) | PCATCH,
270 devopn, 0))) {
271 splx(s);
272 return (error);
273 }
274 #endif
275
276 mask = 1 << part;
277
278 switch (fmt) {
279 case S_IFCHR:
280 ra->ra_disk.dk_copenmask |= mask;
281 break;
282 case S_IFBLK:
283 ra->ra_disk.dk_bopenmask |= mask;
284 break;
285 }
286 ra->ra_disk.dk_openmask |= mask;
287 error = 0;
288 bad1:
289 mutex_exit(&ra->ra_disk.dk_openlock);
290 return (error);
291 }
292
293 /* ARGSUSED */
294 int
295 raclose(dev_t dev, int flags, int fmt, struct lwp *l)
296 {
297 struct ra_softc *ra = mscp_device_lookup(dev);
298 int mask = (1 << DISKPART(dev));
299
300 mutex_enter(&ra->ra_disk.dk_openlock);
301
302 switch (fmt) {
303 case S_IFCHR:
304 ra->ra_disk.dk_copenmask &= ~mask;
305 break;
306 case S_IFBLK:
307 ra->ra_disk.dk_bopenmask &= ~mask;
308 break;
309 }
310 ra->ra_disk.dk_openmask =
311 ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask;
312
313 /*
314 * Should wait for I/O to complete on this partition even if
315 * others are open, but wait for work on blkflush().
316 */
317 #if notyet
318 if (ra->ra_openpart == 0) {
319 s = spluba();
320 while (bufq_peek(udautab[unit]) != NULL)
321 (void) tsleep(&udautab[unit], PZERO - 1,
322 "raclose", 0);
323 splx(s);
324 ra->ra_state = DK_CLOSED;
325 ra->ra_wlabel = 0;
326 }
327 #endif
328 mutex_exit(&ra->ra_disk.dk_openlock);
329 return (0);
330 }
331
332 /*
333 * Queue a transfer request, and if possible, hand it to the controller.
334 */
335 void
336 rastrategy(struct buf *bp)
337 {
338 struct ra_softc *ra = mscp_device_lookup(bp->b_dev);
339 int b;
340
341 /*
342 * Make sure this is a reasonable drive to use.
343 */
344 if (ra == NULL) {
345 bp->b_error = ENXIO;
346 goto done;
347 }
348 /*
349 * If drive is open `raw' or reading label, let it at it.
350 */
351 if (ra->ra_state == DK_RDLABEL) {
352 /* Make some statistics... /bqt */
353 b = splbio();
354 disk_busy(&ra->ra_disk);
355 splx(b);
356 mscp_strategy(bp, device_parent(ra->ra_dev));
357 return;
358 }
359
360 /* If disk is not online, try to put it online */
361 if (ra->ra_state == DK_CLOSED)
362 if (ra_putonline(bp->b_dev, ra) == MSCP_FAILED) {
363 bp->b_error = EIO;
364 goto done;
365 }
366
367 /*
368 * Determine the size of the transfer, and make sure it is
369 * within the boundaries of the partition.
370 */
371 if (bounds_check_with_label(&ra->ra_disk, bp, ra->ra_wlabel) <= 0)
372 goto done;
373
374 /* Make some statistics... /bqt */
375 b = splbio();
376 disk_busy(&ra->ra_disk);
377 splx(b);
378 mscp_strategy(bp, device_parent(ra->ra_dev));
379 return;
380
381 done:
382 biodone(bp);
383 }
384
385 int
386 raread(dev_t dev, struct uio *uio, int flags)
387 {
388
389 return (physio(rastrategy, NULL, dev, B_READ, minphys, uio));
390 }
391
392 int
393 rawrite(dev_t dev, struct uio *uio, int flags)
394 {
395
396 return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio));
397 }
398
399 /*
400 * I/O controls.
401 */
402 int
403 raioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
404 {
405 struct disklabel *lp, *tp;
406 struct ra_softc *ra = mscp_device_lookup(dev);
407 int error = 0;
408 #ifdef __HAVE_OLD_DISKLABEL
409 struct disklabel newlabel;
410 #endif
411
412 lp = ra->ra_disk.dk_label;
413
414 switch (cmd) {
415
416 case DIOCGDINFO:
417 memcpy(data, lp, sizeof (struct disklabel));
418 break;
419 #ifdef __HAVE_OLD_DISKLABEL
420 case ODIOCGDINFO:
421 memcpy(&newlabel, lp, sizeof newlabel);
422 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
423 return ENOTTY;
424 memcpy(data, &newlabel, sizeof (struct olddisklabel));
425 break;
426 #endif
427
428 case DIOCGPART:
429 ((struct partinfo *)data)->disklab = lp;
430 ((struct partinfo *)data)->part =
431 &lp->d_partitions[DISKPART(dev)];
432 break;
433
434 case DIOCWDINFO:
435 case DIOCSDINFO:
436 #ifdef __HAVE_OLD_DISKLABEL
437 case ODIOCWDINFO:
438 case ODIOCSDINFO:
439 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
440 memset(&newlabel, 0, sizeof newlabel);
441 memcpy(&newlabel, data, sizeof (struct olddisklabel));
442 tp = &newlabel;
443 } else
444 #endif
445 tp = (struct disklabel *)data;
446
447 if ((flag & FWRITE) == 0)
448 error = EBADF;
449 else {
450 mutex_enter(&ra->ra_disk.dk_openlock);
451 error = setdisklabel(lp, tp, 0, 0);
452 if ((error == 0) && (cmd == DIOCWDINFO
453 #ifdef __HAVE_OLD_DISKLABEL
454 || cmd == ODIOCWDINFO
455 #endif
456 )) {
457 ra->ra_wlabel = 1;
458 error = writedisklabel(dev, rastrategy, lp,0);
459 ra->ra_wlabel = 0;
460 }
461 mutex_exit(&ra->ra_disk.dk_openlock);
462 }
463 break;
464
465 case DIOCWLABEL:
466 if ((flag & FWRITE) == 0)
467 error = EBADF;
468 else
469 ra->ra_wlabel = 1;
470 break;
471
472 case DIOCGDEFLABEL:
473 #ifdef __HAVE_OLD_DISKLABEL
474 case ODIOCGDEFLABEL:
475 if (cmd == ODIOCGDEFLABEL)
476 tp = &newlabel;
477 else
478 #endif
479 tp = (struct disklabel *)data;
480 memset(tp, 0, sizeof(struct disklabel));
481 tp->d_secsize = lp->d_secsize;
482 tp->d_nsectors = lp->d_nsectors;
483 tp->d_ntracks = lp->d_ntracks;
484 tp->d_ncylinders = lp->d_ncylinders;
485 tp->d_secpercyl = lp->d_secpercyl;
486 tp->d_secperunit = lp->d_secperunit;
487 tp->d_type = DTYPE_MSCP;
488 tp->d_rpm = 3600;
489 rrmakelabel(tp, ra->ra_mediaid);
490 #ifdef __HAVE_OLD_DISKLABEL
491 if (cmd == ODIOCGDEFLABEL) {
492 if (tp->d_npartitions > OLDMAXPARTITIONS)
493 return ENOTTY;
494 memcpy(data, tp, sizeof (struct olddisklabel));
495 }
496 #endif
497 break;
498
499 case DIOCAWEDGE:
500 {
501 struct dkwedge_info *dkw = (void *) data;
502
503 if ((flag & FWRITE) == 0)
504 return (EBADF);
505
506 /* If the ioctl happens here, the parent is us. */
507 strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev),
508 sizeof(dkw->dkw_parent));
509 return (dkwedge_add(dkw));
510 }
511
512 case DIOCDWEDGE:
513 {
514 struct dkwedge_info *dkw = (void *) data;
515
516 if ((flag & FWRITE) == 0)
517 return (EBADF);
518
519 /* If the ioctl happens here, the parent is us. */
520 strlcpy(dkw->dkw_parent, device_xname(ra->ra_dev),
521 sizeof(dkw->dkw_parent));
522 return (dkwedge_del(dkw));
523 }
524
525 case DIOCLWEDGES:
526 {
527 struct dkwedge_list *dkwl = (void *) data;
528
529 return (dkwedge_list(&ra->ra_disk, dkwl, l));
530 }
531
532 default:
533 error = ENOTTY;
534 break;
535 }
536 return (error);
537 }
538
539 int
540 radump(dev_t dev, daddr_t blkno, void *va, size_t size)
541 {
542 return ENXIO;
543 }
544
545 /*
546 * Return the size of a partition, if known, or -1 if not.
547 */
548 int
549 rasize(dev_t dev)
550 {
551 struct ra_softc *ra = mscp_device_lookup(dev);
552
553 if (!ra)
554 return -1;
555
556 if (ra->ra_state == DK_CLOSED)
557 if (ra_putonline(dev, ra) == MSCP_FAILED)
558 return -1;
559
560 return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
561 (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
562 }
563
564 #endif /* NRA || NRACD || NRX */
565
566 #if NRX
567
568 int rxmatch(device_t, cfdata_t, void *);
569
570 CFATTACH_DECL_NEW(rx, sizeof(struct rx_softc),
571 rxmatch, raattach, NULL, NULL);
572
573 dev_type_open(rxopen);
574 dev_type_read(rxread);
575 dev_type_write(rxwrite);
576 dev_type_ioctl(rxioctl);
577 dev_type_strategy(rxstrategy);
578 dev_type_dump(radump);
579 dev_type_size(rxsize);
580
581 const struct bdevsw rx_bdevsw = {
582 .d_open = rxopen,
583 .d_close = nullclose,
584 .d_strategy = rxstrategy,
585 .d_ioctl = rxioctl,
586 .d_dump = radump,
587 .d_psize = rxsize,
588 .d_discard = nodiscard,
589 .d_flag = D_DISK
590 };
591
592 const struct cdevsw rx_cdevsw = {
593 .d_open = rxopen,
594 .d_close = nullclose,
595 .d_read = rxread,
596 .d_write = rxwrite,
597 .d_ioctl = rxioctl,
598 .d_stop = nostop,
599 .d_tty = notty,
600 .d_poll = nopoll,
601 .d_mmap = nommap,
602 .d_kqfilter = nokqfilter,
603 .d_flag = D_DISK
604 };
605
606 static struct dkdriver rxdkdriver = {
607 rxstrategy, minphys
608 };
609
610 /*
611 * More driver definitions, for generic MSCP code.
612 */
613
614 int
615 rxmatch(device_t parent, cfdata_t cf, void *aux)
616 {
617 struct drive_attach_args *da = aux;
618 struct mscp *mp = da->da_mp;
619
620 if ((da->da_typ & MSCPBUS_DISK) == 0)
621 return 0;
622 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
623 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
624 return 0;
625 /*
626 * Check if this disk is a floppy (RX)
627 * Seems to be a safe way to test it per Chris Torek.
628 */
629 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
630 return 1;
631 return 0;
632 }
633
634 #endif /* NRX */
635
636 #if NRACD
637
638 /* Use almost all ra* routines for racd */
639
640 int racdmatch(device_t, cfdata_t, void *);
641
642 CFATTACH_DECL_NEW(racd, sizeof(struct racd_softc),
643 racdmatch, raattach, NULL, NULL);
644
645 dev_type_open(raopen);
646 dev_type_read(raread);
647 dev_type_write(rawrite);
648 dev_type_ioctl(raioctl);
649 dev_type_strategy(rastrategy);
650 dev_type_dump(radump);
651 dev_type_size(rasize);
652
653 const struct bdevsw racd_bdevsw = {
654 .d_open = raopen,
655 .d_close = nullclose,
656 .d_strategy = rastrategy,
657 .d_ioctl = raioctl,
658 .d_dump = radump,
659 .d_psize = rasize,
660 .d_discard = nodiscard,
661 .d_flag = D_DISK
662 };
663
664 const struct cdevsw racd_cdevsw = {
665 .d_open = raopen,
666 .d_close = nullclose,
667 .d_read = raread,
668 .d_write = rawrite,
669 .d_ioctl = raioctl,
670 .d_stop = nostop,
671 .d_tty = notty,
672 .d_poll = nopoll,
673 .d_mmap = nommap,
674 .d_kqfilter = nokqfilter,
675 .d_flag = D_DISK
676 };
677
678 static struct dkdriver racddkdriver = {
679 rastrategy, minphys
680 };
681
682 /*
683 * More driver definitions, for generic MSCP code.
684 */
685
686 int
687 racdmatch(device_t parent, cfdata_t cf, void *aux)
688 {
689 struct drive_attach_args *da = aux;
690 struct mscp *mp = da->da_mp;
691
692 if ((da->da_typ & MSCPBUS_DISK) == 0)
693 return 0;
694 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
695 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
696 return 0;
697 /*
698 * Check if this disk is a CD (RRD)
699 */
700 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
701 return 1;
702 return 0;
703 }
704
705 #endif /* NRACD */
706
707 /*
708 * The attach routine only checks and prints drive type.
709 * Bringing the disk online is done when the disk is accessed
710 * the first time.
711 */
712 void
713 raattach(device_t parent, device_t self, void *aux)
714 {
715 struct rx_softc *rx = device_private(self);
716 struct drive_attach_args *da = aux;
717 struct mscp *mp = da->da_mp;
718 struct mscp_softc *mi = device_private(parent);
719 struct disklabel *dl;
720
721 rx->ra_dev = self;
722 rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
723 rx->ra_state = DK_CLOSED;
724 rx->ra_hwunit = mp->mscp_unit;
725 mi->mi_dp[mp->mscp_unit] = self;
726
727 #if NRX
728 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
729 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
730 &rxdkdriver);
731 #endif
732 #if NRACD
733 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
734 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
735 &racddkdriver);
736 #endif
737 #if NRA
738 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@' &&
739 MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'R' - '@')
740 disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
741 &radkdriver);
742 #endif
743 disk_attach(&rx->ra_disk);
744
745 /* Fill in what we know. The actual size is gotten later */
746 dl = rx->ra_disk.dk_label;
747
748 dl->d_secsize = DEV_BSIZE;
749 dl->d_nsectors = mp->mscp_guse.guse_nspt;
750 dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
751 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
752 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
753 #ifdef DEBUG
754 printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
755 device_xname(self), mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
756 mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
757 mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
758 #endif
759 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@') {
760 /*
761 * XXX We should try to discover wedges here, but
762 * XXX that would mean being able to do I/O. Should
763 * XXX use config_defer() here.
764 */
765 }
766 }
767
768 /*
769 * (Try to) put the drive online. This is done the first time the
770 * drive is opened, or if it har fallen offline.
771 */
772 int
773 rx_putonline(struct rx_softc *rx)
774 {
775 struct mscp *mp;
776 struct mscp_softc *mi = device_private(device_parent(rx->ra_dev));
777
778 rx->ra_state = DK_CLOSED;
779 mp = mscp_getcp(mi, MSCP_WAIT);
780 mp->mscp_opcode = M_OP_ONLINE;
781 mp->mscp_unit = rx->ra_hwunit;
782 mp->mscp_cmdref = 1;
783 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
784
785 /* Poll away */
786 bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
787 if (tsleep(&rx->ra_state, PRIBIO, "rxonline", 100*100))
788 rx->ra_state = DK_CLOSED;
789
790 if (rx->ra_state == DK_CLOSED)
791 return MSCP_FAILED;
792
793 return MSCP_DONE;
794 }
795
796 #if NRX
797
798 /*
799 * Open a drive.
800 */
801 /*ARGSUSED*/
802 int
803 rxopen(dev_t dev, int flag, int fmt, struct lwp *l)
804 {
805 struct rx_softc *rx;
806 int unit;
807
808 /*
809 * Make sure this is a reasonable open request.
810 */
811 unit = DISKUNIT(dev);
812 rx = device_lookup_private(&rx_cd, unit);
813 if (!rx)
814 return ENXIO;
815
816 /*
817 * If this is the first open; we must first try to put
818 * the disk online (and read the label).
819 */
820 if (rx->ra_state == DK_CLOSED)
821 if (rx_putonline(rx) == MSCP_FAILED)
822 return ENXIO;
823
824 return 0;
825 }
826
827 /*
828 * Queue a transfer request, and if possible, hand it to the controller.
829 *
830 * This routine is broken into two so that the internal version
831 * udastrat1() can be called by the (nonexistent, as yet) bad block
832 * revectoring routine.
833 */
834 void
835 rxstrategy(struct buf *bp)
836 {
837 int unit;
838 struct rx_softc *rx;
839 int b;
840
841 /*
842 * Make sure this is a reasonable drive to use.
843 */
844 unit = DISKUNIT(bp->b_dev);
845 if ((rx = device_lookup_private(&rx_cd, unit)) == NULL) {
846 bp->b_error = ENXIO;
847 goto done;
848 }
849
850 /* If disk is not online, try to put it online */
851 if (rx->ra_state == DK_CLOSED)
852 if (rx_putonline(rx) == MSCP_FAILED) {
853 bp->b_error = EIO;
854 goto done;
855 }
856
857 /*
858 * Determine the size of the transfer, and make sure it is
859 * within the boundaries of the partition.
860 */
861 if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
862 bp->b_resid = bp->b_bcount;
863 goto done;
864 }
865
866 /* Make some statistics... /bqt */
867 b = splbio();
868 disk_busy(&rx->ra_disk);
869 splx(b);
870 mscp_strategy(bp, device_parent(rx->ra_dev));
871 return;
872
873 done:
874 biodone(bp);
875 }
876
877 int
878 rxread(dev_t dev, struct uio *uio, int flag)
879 {
880
881 return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
882 }
883
884 int
885 rxwrite(dev_t dev, struct uio *uio, int flag)
886 {
887
888 return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
889 }
890
891 /*
892 * I/O controls.
893 */
894 int
895 rxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
896 {
897 int unit = DISKUNIT(dev);
898 struct disklabel *lp;
899 struct rx_softc *rx = device_lookup_private(&rx_cd, unit);
900 int error = 0;
901
902 lp = rx->ra_disk.dk_label;
903
904 switch (cmd) {
905
906 case DIOCGDINFO:
907 memcpy(data, lp, sizeof (struct disklabel));
908 break;
909
910 case DIOCGPART:
911 ((struct partinfo *)data)->disklab = lp;
912 ((struct partinfo *)data)->part =
913 &lp->d_partitions[DISKPART(dev)];
914 break;
915
916
917 case DIOCWDINFO:
918 case DIOCSDINFO:
919 case DIOCWLABEL:
920 break;
921
922 default:
923 error = ENOTTY;
924 break;
925 }
926 return (error);
927 }
928
929 int
930 rxsize(dev_t dev)
931 {
932
933 return -1;
934 }
935
936 #endif /* NRX */
937
938 void rrdgram(device_t, struct mscp *, struct mscp_softc *);
939 void rriodone(device_t, struct buf *);
940 int rronline(device_t, struct mscp *);
941 int rrgotstatus(device_t, struct mscp *);
942 void rrreplace(device_t, struct mscp *);
943 int rrioerror(device_t, struct mscp *, struct buf *);
944 void rrfillin(struct buf *, struct mscp *);
945 void rrbb(device_t, struct mscp *, struct buf *);
946
947
948 struct mscp_device ra_device = {
949 rrdgram,
950 rriodone,
951 rronline,
952 rrgotstatus,
953 rrreplace,
954 rrioerror,
955 rrbb,
956 rrfillin,
957 };
958
959 /*
960 * Handle an error datagram.
961 * This can come from an unconfigured drive as well.
962 */
963 void
964 rrdgram(device_t usc, struct mscp *mp, struct mscp_softc *mi)
965 {
966 if (mscp_decodeerror(usc == NULL?"unconf disk" : device_xname(usc), mp, mi))
967 return;
968 /*
969 * SDI status information bytes 10 and 11 are the microprocessor
970 * error code and front panel code respectively. These vary per
971 * drive type and are printed purely for field service information.
972 */
973 if (mp->mscp_format == M_FM_SDI)
974 printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
975 mp->mscp_erd.erd_sdistat[10],
976 mp->mscp_erd.erd_sdistat[11]);
977 }
978
979
980 void
981 rriodone(device_t usc, struct buf *bp)
982 {
983 struct ra_softc *ra = device_private(usc);
984
985 disk_unbusy(&ra->ra_disk, bp->b_bcount, (bp->b_flags & B_READ));
986
987 biodone(bp);
988 }
989
990 /*
991 * A drive came on line. Check its type and size. Return DONE if
992 * we think the drive is truly on line. In any case, awaken anyone
993 * sleeping on the drive on-line-ness.
994 */
995 int
996 rronline(device_t usc, struct mscp *mp)
997 {
998 struct ra_softc *ra = device_private(usc);
999 struct disklabel *dl;
1000
1001 wakeup((void *)&ra->ra_state);
1002 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
1003 aprint_error_dev(usc, "attempt to bring on line failed: ");
1004 mscp_printevent(mp);
1005 return (MSCP_FAILED);
1006 }
1007
1008 ra->ra_state = DK_OPEN;
1009
1010 dl = ra->ra_disk.dk_label;
1011 dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
1012
1013 if (dl->d_secpercyl) {
1014 dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
1015 dl->d_type = DTYPE_MSCP;
1016 dl->d_rpm = 3600;
1017 } else {
1018 dl->d_type = DTYPE_FLOPPY;
1019 dl->d_rpm = 300;
1020 }
1021 rrmakelabel(dl, ra->ra_mediaid);
1022
1023 return (MSCP_DONE);
1024 }
1025
1026 void
1027 rrmakelabel(struct disklabel *dl, long type)
1028 {
1029 int n, p = 0;
1030
1031 dl->d_bbsize = BBSIZE;
1032 dl->d_sbsize = SBLOCKSIZE;
1033
1034 /* Create the disk name for disklabel. Phew... */
1035 dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
1036 dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
1037 if (MSCP_MID_ECH(0, type))
1038 dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
1039 n = MSCP_MID_NUM(type);
1040 if (n > 99) {
1041 dl->d_typename[p++] = '1';
1042 n -= 100;
1043 }
1044 if (n > 9) {
1045 dl->d_typename[p++] = (n / 10) + '0';
1046 n %= 10;
1047 }
1048 dl->d_typename[p++] = n + '0';
1049 dl->d_typename[p] = 0;
1050 dl->d_npartitions = MAXPARTITIONS;
1051 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
1052 dl->d_secperunit;
1053 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
1054 dl->d_interleave = dl->d_headswitch = 1;
1055 dl->d_magic = dl->d_magic2 = DISKMAGIC;
1056 dl->d_checksum = dkcksum(dl);
1057 }
1058
1059 /*
1060 * We got some (configured) unit's status. Return DONE if it succeeded.
1061 */
1062 int
1063 rrgotstatus(device_t usc, struct mscp *mp)
1064 {
1065 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
1066 aprint_error_dev(usc, "attempt to get status failed: ");
1067 mscp_printevent(mp);
1068 return (MSCP_FAILED);
1069 }
1070 /* record for (future) bad block forwarding and whatever else */
1071 #ifdef notyet
1072 uda_rasave(ui->ui_unit, mp, 1);
1073 #endif
1074 return (MSCP_DONE);
1075 }
1076
1077 /*
1078 * A replace operation finished.
1079 */
1080 /*ARGSUSED*/
1081 void
1082 rrreplace(device_t usc, struct mscp *mp)
1083 {
1084
1085 panic("udareplace");
1086 }
1087
1088 /*
1089 * A transfer failed. We get a chance to fix or restart it.
1090 * Need to write the bad block forwaring code first....
1091 */
1092 /*ARGSUSED*/
1093 int
1094 rrioerror(device_t usc, struct mscp *mp, struct buf *bp)
1095 {
1096 struct ra_softc *ra = device_private(usc);
1097 int code = mp->mscp_event;
1098
1099 switch (code & M_ST_MASK) {
1100 /* The unit has fallen offline. Try to figure out why. */
1101 case M_ST_OFFLINE:
1102 bp->b_error = EIO;
1103 ra->ra_state = DK_CLOSED;
1104 if (code & M_OFFLINE_UNMOUNTED)
1105 aprint_error_dev(usc, "not mounted/spun down\n");
1106 if (code & M_OFFLINE_DUPLICATE)
1107 aprint_error_dev(usc, "duplicate unit number!!!\n");
1108 return MSCP_DONE;
1109
1110 case M_ST_AVAILABLE:
1111 ra->ra_state = DK_CLOSED; /* Force another online */
1112 return MSCP_DONE;
1113
1114 default:
1115 printf("%s:", device_xname(usc));
1116 break;
1117 }
1118 return (MSCP_FAILED);
1119 }
1120
1121 /*
1122 * Fill in disk addresses in a mscp packet waiting for transfer.
1123 */
1124 void
1125 rrfillin(struct buf *bp, struct mscp *mp)
1126 {
1127 struct ra_softc *ra;
1128 struct disklabel *lp;
1129 int part = DISKPART(bp->b_dev);
1130
1131 ra = mscp_device_lookup(bp->b_dev);
1132 lp = ra->ra_disk.dk_label;
1133
1134 mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
1135 mp->mscp_unit = ra->ra_hwunit;
1136 mp->mscp_seq.seq_bytecount = bp->b_bcount;
1137 }
1138
1139 /*
1140 * A bad block related operation finished.
1141 */
1142 /*ARGSUSED*/
1143 void
1144 rrbb(device_t usc, struct mscp *mp, struct buf *bp)
1145 {
1146
1147 panic("udabb");
1148 }
1149
1150 /*
1151 * (Try to) put the drive online. This is done the first time the
1152 * drive is opened, or if it has fallen offline.
1153 */
1154 int
1155 ra_putonline(dev_t dev, struct ra_softc *ra)
1156 {
1157 struct disklabel *dl;
1158 const char *msg;
1159
1160 if (rx_putonline(ra) != MSCP_DONE)
1161 return MSCP_FAILED;
1162
1163 dl = ra->ra_disk.dk_label;
1164
1165 ra->ra_state = DK_RDLABEL;
1166 printf("%s", device_xname(ra->ra_dev));
1167 if ((msg = readdisklabel(
1168 MAKEDISKDEV(major(dev), device_unit(ra->ra_dev), RAW_PART),
1169 rastrategy, dl, NULL)) == NULL) {
1170 ra->ra_havelabel = 1;
1171 ra->ra_state = DK_OPEN;
1172 }
1173 #if NRACD
1174 else if (cdevsw_lookup(dev) == &racd_cdevsw) {
1175 dl->d_partitions[0].p_offset = 0;
1176 dl->d_partitions[0].p_size = dl->d_secperunit;
1177 dl->d_partitions[0].p_fstype = FS_ISO9660;
1178 }
1179 #endif /* NRACD */
1180 else {
1181 printf(": %s", msg);
1182 }
1183
1184 printf(": size %d sectors\n", dl->d_secperunit);
1185
1186 return MSCP_DONE;
1187 }
1188
1189
1190 static inline struct ra_softc *
1191 mscp_device_lookup(dev_t dev)
1192 {
1193 struct ra_softc *ra;
1194 int unit;
1195
1196 unit = DISKUNIT(dev);
1197 #if NRA
1198 if (cdevsw_lookup(dev) == &ra_cdevsw)
1199 ra = device_lookup_private(&ra_cd, unit);
1200 else
1201 #endif
1202 #if NRACD
1203 if (cdevsw_lookup(dev) == &racd_cdevsw)
1204 ra = device_lookup_private(&racd_cd, unit);
1205 else
1206 #endif
1207 #if NRX
1208 if (cdevsw_lookup(dev) == &rx_cdevsw)
1209 ra = device_lookup_private(&rx_cd, unit);
1210 else
1211 #endif
1212 panic("mscp_device_lookup: unexpected major %"PRIu32" unit %u",
1213 major(dev), unit);
1214 return ra;
1215 }
1216