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