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