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