mscp_disk.c revision 1.64 1 /* $NetBSD: mscp_disk.c,v 1.64 2009/03/14 15:36:19 dsl 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 */
77
78 /*
79 * TODO
80 * write bad block forwarding code
81 */
82
83 #include <sys/cdefs.h>
84 __KERNEL_RCSID(0, "$NetBSD: mscp_disk.c,v 1.64 2009/03/14 15:36:19 dsl Exp $");
85
86 #include <sys/param.h>
87 #include <sys/buf.h>
88 #include <sys/bufq.h>
89 #include <sys/device.h>
90 #include <sys/disk.h>
91 #include <sys/disklabel.h>
92 #include <sys/ioctl.h>
93 #include <sys/stat.h>
94 #include <sys/fcntl.h>
95 #include <sys/reboot.h>
96 #include <sys/proc.h>
97 #include <sys/systm.h>
98 #include <sys/conf.h>
99
100 #include <ufs/ufs/dinode.h>
101 #include <ufs/ffs/fs.h>
102
103 #include <sys/bus.h>
104 #include <sys/cpu.h>
105
106 #include <dev/mscp/mscp.h>
107 #include <dev/mscp/mscpreg.h>
108 #include <dev/mscp/mscpvar.h>
109
110 #include "locators.h"
111 #include "ioconf.h"
112 #include "ra.h"
113
114 /*
115 * Drive status, per drive
116 */
117 struct ra_softc {
118 struct device ra_dev; /* Autoconf struct */
119 struct disk ra_disk;
120 int ra_state; /* open/closed state */
121 u_long ra_mediaid; /* media id */
122 int ra_hwunit; /* Hardware unit number */
123 int ra_havelabel; /* true if we have a label */
124 int ra_wlabel; /* label sector is currently writable */
125 };
126
127 #define rx_softc ra_softc
128
129 void rxattach(struct device *, struct device *, void *);
130 int rx_putonline(struct rx_softc *);
131 void rrmakelabel(struct disklabel *, long);
132
133 #if NRA
134
135 int ramatch(struct device *, struct cfdata *, void *);
136 void raattach(struct device *, struct device *, void *);
137 int ra_putonline(struct ra_softc *);
138
139 CFATTACH_DECL(ra, sizeof(struct ra_softc),
140 ramatch, rxattach, NULL, NULL);
141
142 dev_type_open(raopen);
143 dev_type_close(raclose);
144 dev_type_read(raread);
145 dev_type_write(rawrite);
146 dev_type_ioctl(raioctl);
147 dev_type_strategy(rastrategy);
148 dev_type_dump(radump);
149 dev_type_size(rasize);
150
151 const struct bdevsw ra_bdevsw = {
152 raopen, raclose, rastrategy, raioctl, radump, rasize, D_DISK
153 };
154
155 const struct cdevsw ra_cdevsw = {
156 raopen, raclose, raread, rawrite, raioctl,
157 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
158 };
159
160 static struct dkdriver radkdriver = {
161 rastrategy, minphys
162 };
163
164 /*
165 * More driver definitions, for generic MSCP code.
166 */
167
168 int
169 ramatch(struct device *parent, struct cfdata *cf, void *aux)
170 {
171 struct drive_attach_args *da = aux;
172 struct mscp *mp = da->da_mp;
173
174 if ((da->da_typ & MSCPBUS_DISK) == 0)
175 return 0;
176 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
177 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
178 return 0;
179 /*
180 * Check if this disk is a floppy; then don't configure it.
181 * Seems to be a safe way to test it per Chris Torek.
182 */
183 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
184 return 0;
185 return 1;
186 }
187
188 /*
189 * (Try to) put the drive online. This is done the first time the
190 * drive is opened, or if it har fallen offline.
191 */
192 int
193 ra_putonline(struct ra_softc *ra)
194 {
195 struct disklabel *dl;
196 const char *msg;
197 int maj;
198
199 if (rx_putonline(ra) != MSCP_DONE)
200 return MSCP_FAILED;
201
202 dl = ra->ra_disk.dk_label;
203
204 ra->ra_state = DK_RDLABEL;
205 printf("%s", device_xname(&ra->ra_dev));
206 maj = cdevsw_lookup_major(&ra_cdevsw);
207 if ((msg = readdisklabel(MAKEDISKDEV(maj, device_unit(&ra->ra_dev),
208 RAW_PART), rastrategy, dl, NULL)) != NULL)
209 printf(": %s", msg);
210 else {
211 ra->ra_havelabel = 1;
212 ra->ra_state = DK_OPEN;
213 }
214
215 printf(": size %d sectors\n", dl->d_secperunit);
216
217 return MSCP_DONE;
218 }
219
220 /*
221 * Open a drive.
222 */
223 /*ARGSUSED*/
224 int
225 raopen(dev, flag, fmt, l)
226 dev_t dev;
227 int flag, fmt;
228 struct lwp *l;
229 {
230 struct ra_softc *ra;
231 int error, part, unit, mask;
232 /*
233 * Make sure this is a reasonable open request.
234 */
235 unit = DISKUNIT(dev);
236 ra = device_lookup_private(&ra_cd, unit);
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(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
304 raclose(dev, flags, fmt, l)
305 dev_t dev;
306 int flags, fmt;
307 struct lwp *l;
308 {
309 int unit = DISKUNIT(dev);
310 struct ra_softc *ra = device_lookup_private(&ra_cd, unit);
311 int mask = (1 << DISKPART(dev));
312
313 mutex_enter(&ra->ra_disk.dk_openlock);
314
315 switch (fmt) {
316 case S_IFCHR:
317 ra->ra_disk.dk_copenmask &= ~mask;
318 break;
319 case S_IFBLK:
320 ra->ra_disk.dk_bopenmask &= ~mask;
321 break;
322 }
323 ra->ra_disk.dk_openmask =
324 ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask;
325
326 /*
327 * Should wait for I/O to complete on this partition even if
328 * others are open, but wait for work on blkflush().
329 */
330 #if notyet
331 if (ra->ra_openpart == 0) {
332 s = spluba();
333 while (bufq_peek(udautab[unit]) != NULL)
334 (void) tsleep(&udautab[unit], PZERO - 1,
335 "raclose", 0);
336 splx(s);
337 ra->ra_state = CLOSED;
338 ra->ra_wlabel = 0;
339 }
340 #endif
341 mutex_exit(&ra->ra_disk.dk_openlock);
342 return (0);
343 }
344
345 /*
346 * Queue a transfer request, and if possible, hand it to the controller.
347 */
348 void
349 rastrategy(struct buf *bp)
350 {
351 int unit;
352 struct ra_softc *ra;
353 int b;
354
355 /*
356 * Make sure this is a reasonable drive to use.
357 */
358 unit = DISKUNIT(bp->b_dev);
359 if ((ra = device_lookup_private(&ra_cd, unit)) == NULL) {
360 bp->b_error = ENXIO;
361 goto done;
362 }
363 /*
364 * If drive is open `raw' or reading label, let it at it.
365 */
366 if (ra->ra_state == DK_RDLABEL) {
367 /* Make some statistics... /bqt */
368 b = splbio();
369 disk_busy(&ra->ra_disk);
370 splx(b);
371 mscp_strategy(bp, device_parent(&ra->ra_dev));
372 return;
373 }
374
375 /* If disk is not online, try to put it online */
376 if (ra->ra_state == DK_CLOSED)
377 if (ra_putonline(ra) == MSCP_FAILED) {
378 bp->b_error = EIO;
379 goto done;
380 }
381
382 /*
383 * Determine the size of the transfer, and make sure it is
384 * within the boundaries of the partition.
385 */
386 if (bounds_check_with_label(&ra->ra_disk, bp, ra->ra_wlabel) <= 0)
387 goto done;
388
389 /* Make some statistics... /bqt */
390 b = splbio();
391 disk_busy(&ra->ra_disk);
392 splx(b);
393 mscp_strategy(bp, device_parent(&ra->ra_dev));
394 return;
395
396 done:
397 biodone(bp);
398 }
399
400 int
401 raread(dev_t dev, struct uio *uio, int flags)
402 {
403
404 return (physio(rastrategy, NULL, dev, B_READ, minphys, uio));
405 }
406
407 int
408 rawrite(dev_t dev, struct uio *uio, int flags)
409 {
410
411 return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio));
412 }
413
414 /*
415 * I/O controls.
416 */
417 int
418 raioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
419 {
420 int unit = DISKUNIT(dev);
421 struct disklabel *lp, *tp;
422 struct ra_softc *ra = device_lookup_private(&ra_cd, unit);
423 int error = 0;
424 #ifdef __HAVE_OLD_DISKLABEL
425 struct disklabel newlabel;
426 #endif
427
428 lp = ra->ra_disk.dk_label;
429
430 switch (cmd) {
431
432 case DIOCGDINFO:
433 bcopy(lp, data, sizeof (struct disklabel));
434 break;
435 #ifdef __HAVE_OLD_DISKLABEL
436 case ODIOCGDINFO:
437 bcopy(lp, &newlabel, sizeof disklabel);
438 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
439 return ENOTTY;
440 bcopy(&newlabel, data, sizeof (struct olddisklabel));
441 break;
442 #endif
443
444 case DIOCGPART:
445 ((struct partinfo *)data)->disklab = lp;
446 ((struct partinfo *)data)->part =
447 &lp->d_partitions[DISKPART(dev)];
448 break;
449
450 case DIOCWDINFO:
451 case DIOCSDINFO:
452 #ifdef __HAVE_OLD_DISKLABEL
453 case ODIOCWDINFO:
454 case ODIOCSDINFO:
455 if (cmd == ODIOCSDINFO || xfer == ODIOCWDINFO) {
456 memset(&newlabel, 0, sizeof newlabel);
457 memcpy(&newlabel, data, sizeof (struct olddisklabel));
458 tp = &newlabel;
459 } else
460 #endif
461 tp = (struct disklabel *)data;
462
463 if ((flag & FWRITE) == 0)
464 error = EBADF;
465 else {
466 mutex_enter(&ra->ra_disk.dk_openlock);
467 error = setdisklabel(lp, tp, 0, 0);
468 if ((error == 0) && (cmd == DIOCWDINFO
469 #ifdef __HAVE_OLD_DISKLABEL
470 || cmd == ODIOCWDINFO
471 #else
472 )) {
473 #endif
474 ra->ra_wlabel = 1;
475 error = writedisklabel(dev, rastrategy, lp,0);
476 ra->ra_wlabel = 0;
477 }
478 mutex_exit(&ra->ra_disk.dk_openlock);
479 }
480 break;
481
482 case DIOCWLABEL:
483 if ((flag & FWRITE) == 0)
484 error = EBADF;
485 else
486 ra->ra_wlabel = 1;
487 break;
488
489 case DIOCGDEFLABEL:
490 #ifdef __HAVE_OLD_DISKLABEL
491 case ODIOCGDEFLABEL:
492 if (cmd == ODIOCGDEFLABEL)
493 tp = &newlabel;
494 else
495 #else
496 tp = (struct disklabel *)data;
497 #endif
498 bzero(tp, sizeof(struct disklabel));
499 tp->d_secsize = lp->d_secsize;
500 tp->d_nsectors = lp->d_nsectors;
501 tp->d_ntracks = lp->d_ntracks;
502 tp->d_ncylinders = lp->d_ncylinders;
503 tp->d_secpercyl = lp->d_secpercyl;
504 tp->d_secperunit = lp->d_secperunit;
505 tp->d_type = DTYPE_MSCP;
506 tp->d_rpm = 3600;
507 rrmakelabel(tp, ra->ra_mediaid);
508 #ifdef __HAVE_OLD_DISKLABEL
509 if (cmd == ODIOCGDEFLABEL) {
510 if (tp->d_npartitions > OLDMAXPARTITIONS)
511 return ENOTTY;
512 memcpy(data, tp, sizeof (struct olddisklabel));
513 }
514 #endif
515 break;
516
517 case DIOCAWEDGE:
518 {
519 struct dkwedge_info *dkw = (void *) data;
520
521 if ((flag & FWRITE) == 0)
522 return (EBADF);
523
524 /* If the ioctl happens here, the parent is us. */
525 strlcpy(dkw->dkw_parent, device_xname(&ra->ra_dev),
526 sizeof(dkw->dkw_parent));
527 return (dkwedge_add(dkw));
528 }
529
530 case DIOCDWEDGE:
531 {
532 struct dkwedge_info *dkw = (void *) data;
533
534 if ((flag & FWRITE) == 0)
535 return (EBADF);
536
537 /* If the ioctl happens here, the parent is us. */
538 strlcpy(dkw->dkw_parent, device_xname(&ra->ra_dev),
539 sizeof(dkw->dkw_parent));
540 return (dkwedge_del(dkw));
541 }
542
543 case DIOCLWEDGES:
544 {
545 struct dkwedge_list *dkwl = (void *) data;
546
547 return (dkwedge_list(&ra->ra_disk, dkwl, l));
548 }
549
550 default:
551 error = ENOTTY;
552 break;
553 }
554 return (error);
555 }
556
557
558 int
559 radump(dev_t dev, daddr_t blkno, void *va, size_t size)
560 {
561 return ENXIO;
562 }
563
564 /*
565 * Return the size of a partition, if known, or -1 if not.
566 */
567 int
568 rasize(dev_t dev)
569 {
570 int unit = DISKUNIT(dev);
571 struct ra_softc *ra;
572
573 ra = device_lookup_private(&ra_cd, unit);
574 if (!ra)
575 return -1;
576
577 if (ra->ra_state == DK_CLOSED)
578 if (ra_putonline(ra) == MSCP_FAILED)
579 return -1;
580
581 return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
582 (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
583 }
584
585 #endif /* NRA */
586
587 #if NRX
588
589 int rxmatch(struct device *, struct cfdata *, void *);
590
591 CFATTACH_DECL(rx, sizeof(struct rx_softc),
592 rxmatch, rxattach, NULL, NULL);
593
594 dev_type_open(rxopen);
595 dev_type_read(rxread);
596 dev_type_write(rxwrite);
597 dev_type_ioctl(rxioctl);
598 dev_type_strategy(rxstrategy);
599 dev_type_dump(rxdump);
600 dev_type_size(rxsize);
601
602 const struct bdevsw rx_bdevsw = {
603 rxopen, nullclose, rxstrategy, rxioctl, rxdump, rxsize, D_DISK
604 };
605
606 const struct cdevsw rx_cdevsw = {
607 rxopen, nullclose, rxread, rxwrite, rxioctl,
608 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
609 };
610
611 static struct dkdriver rxdkdriver = {
612 rxstrategy, minphys
613 };
614
615 /*
616 * More driver definitions, for generic MSCP code.
617 */
618
619 int
620 rxmatch(struct device *parent, struct cfdata *cf, void *aux)
621 {
622 struct drive_attach_args *da = aux;
623 struct mscp *mp = da->da_mp;
624
625 if ((da->da_typ & MSCPBUS_DISK) == 0)
626 return 0;
627 if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
628 cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
629 return 0;
630 /*
631 * Check if this disk is a floppy; then configure it.
632 * Seems to be a safe way to test it per Chris Torek.
633 */
634 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
635 return 1;
636 return 0;
637 }
638
639 #endif /* NRX */
640
641 /*
642 * The attach routine only checks and prints drive type.
643 * Bringing the disk online is done when the disk is accessed
644 * the first time.
645 */
646 void
647 rxattach(parent, self, aux)
648 struct device *parent, *self;
649 void *aux;
650 {
651 struct rx_softc *rx = device_private(self);
652 struct drive_attach_args *da = aux;
653 struct mscp *mp = da->da_mp;
654 struct mscp_softc *mi = (void *)parent;
655 struct disklabel *dl;
656
657 rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
658 rx->ra_state = DK_CLOSED;
659 rx->ra_hwunit = mp->mscp_unit;
660 mi->mi_dp[mp->mscp_unit] = self;
661
662 #if NRX
663 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
664 disk_init((struct disk *)&rx->ra_disk, device_xname(&rx->ra_dev),
665 &rxdkdriver);
666 #endif
667 #if NRA
668 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@')
669 disk_init((struct disk *)&rx->ra_disk, device_xname(&rx->ra_dev),
670 &radkdriver);
671 #endif
672 disk_attach((struct disk *)&rx->ra_disk);
673
674 /* Fill in what we know. The actual size is gotten later */
675 dl = rx->ra_disk.dk_label;
676
677 dl->d_secsize = DEV_BSIZE;
678 dl->d_nsectors = mp->mscp_guse.guse_nspt;
679 dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
680 dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
681 disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
682 #ifdef DEBUG
683 printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
684 device_xname(self), mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
685 mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
686 mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
687 #endif
688 if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@') {
689 /*
690 * XXX We should try to discover wedges here, but
691 * XXX that would mean being able to do I/O. Should
692 * XXX use config_defer() here.
693 */
694 }
695 }
696
697 /*
698 * (Try to) put the drive online. This is done the first time the
699 * drive is opened, or if it har fallen offline.
700 */
701 int
702 rx_putonline(struct rx_softc *rx)
703 {
704 struct mscp *mp;
705 struct mscp_softc *mi =
706 (struct mscp_softc *)device_parent(&rx->ra_dev);
707 volatile int i;
708
709 rx->ra_state = DK_CLOSED;
710 mp = mscp_getcp(mi, MSCP_WAIT);
711 mp->mscp_opcode = M_OP_ONLINE;
712 mp->mscp_unit = rx->ra_hwunit;
713 mp->mscp_cmdref = 1;
714 *mp->mscp_addr |= MSCP_OWN | MSCP_INT;
715
716 /* Poll away */
717 i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
718 if (tsleep(&rx->ra_state, PRIBIO, "rxonline", 100*100))
719 rx->ra_state = DK_CLOSED;
720
721 if (rx->ra_state == DK_CLOSED)
722 return MSCP_FAILED;
723
724 return MSCP_DONE;
725 }
726
727 #if NRX
728
729 /*
730 * Open a drive.
731 */
732 /*ARGSUSED*/
733 int
734 rxopen(dev, flag, fmt, l)
735 dev_t dev;
736 int flag, fmt;
737 struct lwp *l;
738 {
739 struct rx_softc *rx;
740 int unit;
741
742 /*
743 * Make sure this is a reasonable open request.
744 */
745 unit = DISKUNIT(dev);
746 rx = device_lookup_private(&rx_cd, unit);
747 if (!rx)
748 return ENXIO;
749
750 /*
751 * If this is the first open; we must first try to put
752 * the disk online (and read the label).
753 */
754 if (rx->ra_state == DK_CLOSED)
755 if (rx_putonline(rx) == MSCP_FAILED)
756 return ENXIO;
757
758 return 0;
759 }
760
761 /*
762 * Queue a transfer request, and if possible, hand it to the controller.
763 *
764 * This routine is broken into two so that the internal version
765 * udastrat1() can be called by the (nonexistent, as yet) bad block
766 * revectoring routine.
767 */
768 void
769 rxstrategy(struct buf *bp)
770 {
771 int unit;
772 struct rx_softc *rx;
773 int b;
774
775 /*
776 * Make sure this is a reasonable drive to use.
777 */
778 unit = DISKUNIT(bp->b_dev);
779 if ((rx = device_lookup_private(&rx_cd, unit)) == NULL) {
780 bp->b_error = ENXIO;
781 goto done;
782 }
783
784 /* If disk is not online, try to put it online */
785 if (rx->ra_state == DK_CLOSED)
786 if (rx_putonline(rx) == MSCP_FAILED) {
787 bp->b_error = EIO;
788 goto done;
789 }
790
791 /*
792 * Determine the size of the transfer, and make sure it is
793 * within the boundaries of the partition.
794 */
795 if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
796 bp->b_resid = bp->b_bcount;
797 goto done;
798 }
799
800 /* Make some statistics... /bqt */
801 b = splbio();
802 disk_busy(&rx->ra_disk);
803 splx(b);
804 mscp_strategy(bp, device_parent(&rx->ra_dev));
805 return;
806
807 done:
808 biodone(bp);
809 }
810
811 int
812 rxread(dev_t dev, struct uio *uio, int flag)
813 {
814
815 return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
816 }
817
818 int
819 rxwrite(dev_t dev, struct uio *uio, int flag)
820 {
821
822 return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
823 }
824
825 /*
826 * I/O controls.
827 */
828 int
829 rxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
830 {
831 int unit = DISKUNIT(dev);
832 struct disklabel *lp;
833 struct rx_softc *rx = device_lookup_private(&rx_cd, unit);
834 int error = 0;
835
836 lp = rx->ra_disk.dk_label;
837
838 switch (cmd) {
839
840 case DIOCGDINFO:
841 bcopy(lp, data, sizeof (struct disklabel));
842 break;
843
844 case DIOCGPART:
845 ((struct partinfo *)data)->disklab = lp;
846 ((struct partinfo *)data)->part =
847 &lp->d_partitions[DISKPART(dev)];
848 break;
849
850
851 case DIOCWDINFO:
852 case DIOCSDINFO:
853 case DIOCWLABEL:
854 break;
855
856 default:
857 error = ENOTTY;
858 break;
859 }
860 return (error);
861 }
862
863 int
864 rxdump(dev_t dev, daddr_t blkno, void *va, size_t size)
865 {
866
867 /* Not likely. */
868 return ENXIO;
869 }
870
871 int
872 rxsize(dev_t dev)
873 {
874
875 return -1;
876 }
877
878 #endif /* NRX */
879
880 void rrdgram(struct device *, struct mscp *, struct mscp_softc *);
881 void rriodone(struct device *, struct buf *);
882 int rronline(struct device *, struct mscp *);
883 int rrgotstatus(struct device *, struct mscp *);
884 void rrreplace(struct device *, struct mscp *);
885 int rrioerror(struct device *, struct mscp *, struct buf *);
886 void rrfillin(struct buf *, struct mscp *);
887 void rrbb(struct device *, struct mscp *, struct buf *);
888
889
890 struct mscp_device ra_device = {
891 rrdgram,
892 rriodone,
893 rronline,
894 rrgotstatus,
895 rrreplace,
896 rrioerror,
897 rrbb,
898 rrfillin,
899 };
900
901 /*
902 * Handle an error datagram.
903 * This can come from an unconfigured drive as well.
904 */
905 void
906 rrdgram(struct device *usc, struct mscp *mp, struct mscp_softc *mi)
907 {
908 if (mscp_decodeerror(usc == NULL?"unconf disk" : device_xname(usc), mp, mi))
909 return;
910 /*
911 * SDI status information bytes 10 and 11 are the microprocessor
912 * error code and front panel code respectively. These vary per
913 * drive type and are printed purely for field service information.
914 */
915 if (mp->mscp_format == M_FM_SDI)
916 printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
917 mp->mscp_erd.erd_sdistat[10],
918 mp->mscp_erd.erd_sdistat[11]);
919 }
920
921 void
922 rriodone(struct device *usc, struct buf *bp)
923 {
924 struct ra_softc *ra;
925 int unit;
926
927 /* We assume that this is a reasonable drive. ra_strategy should
928 already have verified it. Thus, no checks here... /bqt */
929 unit = DISKUNIT(bp->b_dev);
930 #if NRA
931 if (cdevsw_lookup(bp->b_dev) == &ra_cdevsw)
932 ra = device_lookup_private(&ra_cd, unit);
933 else
934 #endif
935 #if NRX
936 if (cdevsw_lookup(bp->b_dev) == &rx_cdevsw)
937 ra = device_lookup_private(&rx_cd, unit);
938 else
939 #endif
940 panic("rriodone: unexpected major %"PRIu32" unit %u",
941 major(bp->b_dev), unit);
942 disk_unbusy(&ra->ra_disk, bp->b_bcount, (bp->b_flags & B_READ));
943
944 biodone(bp);
945 }
946
947 /*
948 * A drive came on line. Check its type and size. Return DONE if
949 * we think the drive is truly on line. In any case, awaken anyone
950 * sleeping on the drive on-line-ness.
951 */
952 int
953 rronline(struct device *usc, struct mscp *mp)
954 {
955 struct rx_softc *rx = (struct rx_softc *)usc;
956 struct disklabel *dl;
957
958 wakeup((void *)&rx->ra_state);
959 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
960 aprint_error_dev(usc, "attempt to bring on line failed: ");
961 mscp_printevent(mp);
962 return (MSCP_FAILED);
963 }
964
965 rx->ra_state = DK_OPEN;
966
967 dl = rx->ra_disk.dk_label;
968 dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
969
970 if (dl->d_secpercyl) {
971 dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
972 dl->d_type = DTYPE_MSCP;
973 dl->d_rpm = 3600;
974 } else {
975 dl->d_type = DTYPE_FLOPPY;
976 dl->d_rpm = 300;
977 }
978 rrmakelabel(dl, rx->ra_mediaid);
979
980 return (MSCP_DONE);
981 }
982
983 void
984 rrmakelabel(struct disklabel *dl, long type)
985 {
986 int n, p = 0;
987
988 dl->d_bbsize = BBSIZE;
989 dl->d_sbsize = SBLOCKSIZE;
990
991 /* Create the disk name for disklabel. Phew... */
992 dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
993 dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
994 if (MSCP_MID_ECH(0, type))
995 dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
996 n = MSCP_MID_NUM(type);
997 if (n > 99) {
998 dl->d_typename[p++] = '1';
999 n -= 100;
1000 }
1001 if (n > 9) {
1002 dl->d_typename[p++] = (n / 10) + '0';
1003 n %= 10;
1004 }
1005 dl->d_typename[p++] = n + '0';
1006 dl->d_typename[p] = 0;
1007 dl->d_npartitions = MAXPARTITIONS;
1008 dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
1009 dl->d_secperunit;
1010 dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
1011 dl->d_interleave = dl->d_headswitch = 1;
1012 dl->d_magic = dl->d_magic2 = DISKMAGIC;
1013 dl->d_checksum = dkcksum(dl);
1014 }
1015
1016 /*
1017 * We got some (configured) unit's status. Return DONE if it succeeded.
1018 */
1019 int
1020 rrgotstatus(struct device *usc, struct mscp *mp)
1021 {
1022 if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
1023 aprint_error_dev(usc, "attempt to get status failed: ");
1024 mscp_printevent(mp);
1025 return (MSCP_FAILED);
1026 }
1027 /* record for (future) bad block forwarding and whatever else */
1028 #ifdef notyet
1029 uda_rasave(ui->ui_unit, mp, 1);
1030 #endif
1031 return (MSCP_DONE);
1032 }
1033
1034 /*
1035 * A replace operation finished.
1036 */
1037 /*ARGSUSED*/
1038 void
1039 rrreplace(struct device *usc, struct mscp *mp)
1040 {
1041
1042 panic("udareplace");
1043 }
1044
1045 /*
1046 * A transfer failed. We get a chance to fix or restart it.
1047 * Need to write the bad block forwaring code first....
1048 */
1049 /*ARGSUSED*/
1050 int
1051 rrioerror(struct device *usc, struct mscp *mp, struct buf *bp)
1052 {
1053 struct ra_softc *ra = (void *)usc;
1054 int code = mp->mscp_event;
1055
1056 switch (code & M_ST_MASK) {
1057 /* The unit has fallen offline. Try to figure out why. */
1058 case M_ST_OFFLINE:
1059 bp->b_error = EIO;
1060 ra->ra_state = DK_CLOSED;
1061 if (code & M_OFFLINE_UNMOUNTED)
1062 aprint_error_dev(usc, "not mounted/spun down\n");
1063 if (code & M_OFFLINE_DUPLICATE)
1064 aprint_error_dev(usc, "duplicate unit number!!!\n");
1065 return MSCP_DONE;
1066
1067 case M_ST_AVAILABLE:
1068 ra->ra_state = DK_CLOSED; /* Force another online */
1069 return MSCP_DONE;
1070
1071 default:
1072 printf("%s:", device_xname(usc));
1073 break;
1074 }
1075 return (MSCP_FAILED);
1076 }
1077
1078 /*
1079 * Fill in disk addresses in a mscp packet waiting for transfer.
1080 */
1081 void
1082 rrfillin(struct buf *bp, struct mscp *mp)
1083 {
1084 struct rx_softc *rx = 0; /* Wall */
1085 struct disklabel *lp;
1086 int unit = DISKUNIT(bp->b_dev);
1087 int part = DISKPART(bp->b_dev);
1088
1089 #if NRA
1090 if (cdevsw_lookup(bp->b_dev) == &ra_cdevsw)
1091 rx = device_lookup_private(&ra_cd, unit);
1092 #endif
1093 #if NRX
1094 if (cdevsw_lookup(bp->b_dev) == &rx_cdevsw)
1095 rx = device_lookup_private(&rx_cd, unit);
1096 #endif
1097 lp = rx->ra_disk.dk_label;
1098
1099 mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
1100 mp->mscp_unit = rx->ra_hwunit;
1101 mp->mscp_seq.seq_bytecount = bp->b_bcount;
1102 }
1103
1104 /*
1105 * A bad block related operation finished.
1106 */
1107 /*ARGSUSED*/
1108 void
1109 rrbb(struct device *usc, struct mscp *mp, struct buf *bp)
1110 {
1111
1112 panic("udabb");
1113 }
1114