FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/wfd.c
1 /*
2 * Copyright (c) 1997,1998 Junichi Satoh <junichi@astec.co.jp>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY Junichi Satoh ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL Junichi Satoh BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 /*
30 * ATAPI Floppy, LS-120 driver
31 */
32
33 #include "wdc.h"
34 #include "wfd.h"
35 #include "opt_atapi.h"
36
37 #if NWFD > 0 && NWDC > 0 && defined (ATAPI)
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/conf.h>
43 #include <sys/proc.h>
44 #include <sys/malloc.h>
45 #include <sys/buf.h>
46 #include <sys/devicestat.h>
47 #include <sys/disklabel.h>
48 #include <sys/diskslice.h>
49 #include <sys/cdio.h>
50 #ifdef DEVFS
51 #include <sys/devfsext.h>
52 #endif /*DEVFS*/
53
54 #include <i386/isa/atapi.h>
55
56 static d_open_t wfdopen;
57 static d_read_t wfdread;
58 static d_write_t wfdwrite;
59 static d_close_t wfdclose;
60 static d_ioctl_t wfdioctl;
61 static d_strategy_t wfdstrategy;
62
63 #define CDEV_MAJOR 87
64 #define BDEV_MAJOR 1
65
66 static struct cdevsw wfd_cdevsw = {
67 wfdopen, wfdclose, wfdread, wfdwrite,
68 wfdioctl, nostop, nullreset, nodevtotty,
69 seltrue, nommap, wfdstrategy, "wfd",
70 NULL, -1, nodump, nopsize,
71 D_DISK, 0, -1 };
72
73 #ifndef ATAPI_STATIC
74 static
75 #endif
76 int wfdattach(struct atapi*, int, struct atapi_params*, int);
77
78 #define NUNIT (NWDC*2) /* Max. number of devices */
79 #define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
80
81 #define F_BOPEN 0x0001 /* The block device is opened */
82 #define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
83 #define F_DEBUG 0x0004 /* Print debug info */
84
85 /*
86 * LS-120 Capabilities and Mechanical Status Page
87 */
88 struct cappage {
89 /* Mode data header */
90 u_short data_length;
91 u_char medium_type;
92 #define MDT_UNKNOWN 0x00
93 #define MDT_NO_DISC 0x70
94 #define MDT_DOOR_OPEN 0x71
95 #define MDT_FMT_ERROR 0x72
96
97 #define MDT_2DD_UN 0x10
98 #define MDT_2DD 0x11
99 #define MDT_2HD_UN 0x20
100 #define MDT_2HD_12_98 0x22
101 #define MDT_2HD_12 0x23
102 #define MDT_2HD_144 0x24
103 #define MDT_LS120 0x31
104
105 unsigned reserved0 :7;
106 unsigned wp :1; /* Write protect */
107 u_char reserved1[4];
108
109 /* Capabilities page */
110 unsigned page_code :6; /* Page code - Should be 0x5 */
111 #define CAP_PAGE 0x05
112 unsigned reserved1_6 :1; /* Reserved */
113 unsigned ps :1; /* The device is capable of saving the page */
114 u_char page_length; /* Page Length - Should be 0x1e */
115 u_short transfer_rate; /* In kilobits per second */
116 u_char heads, sectors; /* Number of heads, Number of sectors per track */
117 u_short sector_size; /* Byes per sector */
118 u_short cyls; /* Number of cylinders */
119 u_char reserved10[10];
120 u_char motor_delay; /* Motor off delay */
121 u_char reserved21[7];
122 u_short rpm; /* Rotations per minute */
123 u_char reserved30[2];
124 };
125
126 /* misuse a flag to identify format operation */
127 #define B_FORMAT B_XXX
128
129 struct wfd {
130 struct atapi *ata; /* Controller structure */
131 int unit; /* IDE bus drive unit */
132 int lun; /* Logical device unit */
133 int flags; /* Device state flags */
134 int refcnt; /* The number of raw opens */
135 int maxblks; /* transfer size limit */
136 struct buf_queue_head buf_queue; /* Queue of i/o requests */
137 struct atapi_params *param; /* Drive parameters table */
138 struct cappage cap; /* Capabilities page info */
139 char description[80]; /* Device description */
140 #ifdef DEVFS
141 void *cdevs;
142 void *bdevs;
143 #endif
144 struct diskslices *dk_slices; /* virtual drives */
145
146 struct devstat device_stats;
147 };
148
149 static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
150 static int wfdnlun = 0; /* Number of configured drives */
151
152 static void wfd_start (struct wfd *t);
153 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
154 struct atapires result);
155 static void wfd_error (struct wfd *t, struct atapires result);
156 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
157 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
158 u_char a9, char *addr, int count);
159 static void wfd_describe (struct wfd *t);
160 static int wfd_eject (struct wfd *t, int closeit);
161 static void wfdstrategy1(struct buf *bp);
162
163 /*
164 * Dump the array in hexadecimal format for debugging purposes.
165 */
166 static void wfd_dump (int lun, char *label, void *data, int len)
167 {
168 u_char *p = data;
169
170 printf ("wfd%d: %s %x", lun, label, *p++);
171 while (--len > 0)
172 printf ("-%x", *p++);
173 printf ("\n");
174 }
175
176 #ifndef ATAPI_STATIC
177 static
178 #endif
179 int
180 wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
181 {
182 struct wfd *t;
183 struct atapires result;
184 int lun, i;
185
186 #ifdef DEVFS
187 int mynor;
188 #endif
189 if (wfdnlun >= NUNIT) {
190 printf ("wfd: too many units\n");
191 return (0);
192 }
193 if (!atapi_request_immediate) {
194 printf("wfd: configuration error, ATAPI core code not present!\n");
195 printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
196 return (0);
197 }
198 t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
199 if (! t) {
200 printf ("wfd: out of memory\n");
201 return (0);
202 }
203 wfdtab[wfdnlun] = t;
204 bzero (t, sizeof (struct wfd));
205 bufq_init(&t->buf_queue);
206 t->ata = ata;
207 t->unit = unit;
208 lun = t->lun = wfdnlun;
209 t->param = ap;
210 t->flags = F_MEDIA_CHANGED;
211 t->refcnt = 0;
212 if (debug) {
213 t->flags |= F_DEBUG;
214 /* Print params. */
215 wfd_dump (t->lun, "info", ap, sizeof *ap);
216 }
217
218 /* Get drive capabilities. */
219 /* Do it twice to avoid the stale media changed state. */
220 for (i = 0; i < 2; i++) {
221 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
222 0, CAP_PAGE, 0, 0, 0, 0,
223 sizeof (t->cap) >> 8, sizeof (t->cap),
224 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
225 }
226
227 if (result.code == RES_ERR &&
228 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
229 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
230 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
231 sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
232 (char*) &t->cap, sizeof (t->cap));
233
234 /* Some drives have shorter capabilities page. */
235 if (result.code == RES_UNDERRUN)
236 result.code = 0;
237
238 if (result.code == 0) {
239 wfd_describe (t);
240 if (t->flags & F_DEBUG)
241 wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
242 } else
243 return -1;
244
245 /*
246 * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least
247 * is known to lock up if transfers > 64 blocks are
248 * requested.
249 */
250 if (!strcmp(ap->model, "IOMEGA ZIP 100 ATAPI")) {
251 printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n",
252 t->lun);
253 t->maxblks = 64;
254 } else {
255 t->maxblks = 0; /* no limit */
256 }
257
258
259
260 #ifdef DEVFS
261 mynor = dkmakeminor(t->lun, WHOLE_DISK_SLICE, RAW_PART);
262 t->bdevs = devfs_add_devswf(&wfd_cdevsw, mynor,
263 DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
264 "wfd%d", t->lun);
265 t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor,
266 DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
267 "rwfd%d", t->lun);
268 #endif /* DEVFS */
269
270 /*
271 * Export the drive to the devstat interface.
272 */
273 devstat_add_entry(&t->device_stats, "wfd",
274 t->lun, t->cap.sector_size,
275 DEVSTAT_NO_ORDERED_TAGS,
276 DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_IDE,
277 DEVSTAT_PRIORITY_WFD);
278 wfdnlun++;
279 return (1);
280 }
281
282 void wfd_describe (struct wfd *t)
283 {
284 int no_print = 0;
285
286 t->cap.cyls = ntohs (t->cap.cyls);
287 t->cap.sector_size = ntohs (t->cap.sector_size);
288
289 printf ("wfd%d: ", t->lun);
290 switch (t->cap.medium_type) {
291 case MDT_UNKNOWN:
292 printf ("medium type unknown (no disk)");
293 no_print = 1;
294 break;
295 case MDT_2DD_UN:
296 printf ("2DD(capacity unknown) floppy disk loaded");
297 no_print = 1;
298 break;
299 case MDT_2DD:
300 printf ("720KB floppy disk loaded");
301 break;
302 case MDT_2HD_UN:
303 printf ("2HD(capacity unknown) floppy disk loaded");
304 no_print = 1;
305 break;
306 case MDT_2HD_12_98:
307 printf ("1.25MB(PC-9801 format) floppy disk loaded");
308 break;
309 case MDT_2HD_12:
310 printf ("1.2MB floppy disk loaded");
311 break;
312 case MDT_2HD_144:
313 printf ("1.44MB floppy disk loaded");
314 break;
315 case MDT_LS120:
316 printf ("120MB floppy disk loaded");
317 break;
318 case MDT_NO_DISC:
319 printf ("no disc inside");
320 no_print = 1;
321 break;
322 case MDT_DOOR_OPEN:
323 printf ("door open");
324 no_print = 1;
325 break;
326 case MDT_FMT_ERROR:
327 printf ("medium format error");
328 no_print = 1;
329 break;
330 default:
331 printf ("medium type=0x%x", t->cap.medium_type);
332 break;
333 }
334 if (t->cap.wp)
335 printf(", write protected");
336 printf ("\n");
337
338 if (!no_print) {
339 printf ("wfd%d: ", t->lun);
340 printf ("%u cyls", t->cap.cyls);
341 printf (", %u heads, %u S/T", t->cap.heads, t->cap.sectors);
342 printf (", %u B/S", t->cap.sector_size);
343 printf ("\n");
344 }
345 }
346
347 int wfdopen (dev_t dev, int flags, int fmt, struct proc *p)
348 {
349 int lun = UNIT(dev);
350 struct wfd *t;
351 struct atapires result;
352 int errcode = 0;
353 struct disklabel label;
354
355 /* Check that the device number is legal
356 * and the ATAPI driver is loaded. */
357 if (lun >= wfdnlun || ! atapi_request_immediate)
358 return (ENXIO);
359 t = wfdtab[lun];
360
361 t->flags &= ~F_MEDIA_CHANGED;
362 /* Lock the media. */
363 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
364 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
365
366 /* Sense the media type */
367 result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
368 0, CAP_PAGE, 0, 0, 0, 0,
369 sizeof (t->cap) >> 8, sizeof (t->cap),
370 0, 0, 0, 0, 0, 0, 0,
371 (char*) &t->cap, sizeof (t->cap));
372 if (result.code)
373 printf ("wfd%d: Sense the media type is failed.\n", t->lun);
374 else {
375 t->cap.cyls = ntohs (t->cap.cyls);
376 t->cap.sector_size = ntohs (t->cap.sector_size);
377 }
378
379 /* Build label for whole disk. */
380 bzero(&label, sizeof label);
381 label.d_secsize = t->cap.sector_size;
382 label.d_nsectors = t->cap.sectors;
383 label.d_ntracks = t->cap.heads;
384 label.d_ncylinders = t->cap.cyls;
385 label.d_secpercyl = t->cap.heads * t->cap.sectors;
386 label.d_rpm = 720;
387 label.d_secperunit = label.d_secpercyl * t->cap.cyls;
388
389 /* Initialize slice tables. */
390 errcode = dsopen("wfd", dev, fmt, 0, &t->dk_slices, &label,
391 wfdstrategy1, (ds_setgeom_t *)NULL, &wfd_cdevsw);
392 if (errcode != 0)
393 return errcode;
394
395 t->flags |= F_BOPEN;
396 return (0);
397 }
398
399 /*
400 * Close the device. Only called if we are the LAST
401 * occurence of an open device.
402 */
403 int wfdclose (dev_t dev, int flags, int fmt, struct proc *p)
404 {
405 int lun = UNIT(dev);
406 struct wfd *t = wfdtab[lun];
407
408 dsclose(dev, fmt, t->dk_slices);
409 if(!dsisopen(t->dk_slices)) {
410 /* If we were the last open of the entire device, release it. */
411 if (! t->refcnt)
412 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
414 t->flags &= ~F_BOPEN;
415 }
416 return (0);
417 }
418
419 static int
420 wfdread(dev_t dev, struct uio *uio, int ioflag)
421 {
422 return (physio(wfdstrategy, NULL, dev, 1, minphys, uio));
423 }
424
425 static int
426 wfdwrite(dev_t dev, struct uio *uio, int ioflag)
427 {
428 return (physio(wfdstrategy, NULL, dev, 0, minphys, uio));
429 }
430
431 static void
432 wfdstrategy1(struct buf *bp)
433 {
434 /*
435 * XXX - do something to make wdstrategy() but not this block while
436 * we're doing dsinit() and dsioctl().
437 */
438 wfdstrategy(bp);
439 }
440
441 /*
442 * Actually translate the requested transfer into one the physical driver can
443 * understand. The transfer is described by a buf and will include only one
444 * physical transfer.
445 */
446 void wfdstrategy (struct buf *bp)
447 {
448 int lun = UNIT(bp->b_dev);
449 struct wfd *t = wfdtab[lun];
450 int x;
451
452 /* If it's a null transfer, return immediatly. */
453 if (bp->b_bcount == 0) {
454 bp->b_resid = 0;
455 biodone (bp);
456 return;
457 }
458
459 /*
460 * Do bounds checking, adjust transfer, and set b_pblkno.
461 */
462 if (dscheck(bp, t->dk_slices) <= 0) {
463 biodone(bp);
464 return;
465 }
466
467 x = splbio();
468
469 /* Place it in the queue of disk activities for this disk. */
470 bufqdisksort (&t->buf_queue, bp);
471
472 /* Tell the device to get going on the transfer if it's
473 * not doing anything, otherwise just wait for completion. */
474 wfd_start (t);
475 splx(x);
476 }
477
478 /*
479 * Look to see if there is a buf waiting for the device
480 * and that the device is not already busy. If both are true,
481 * It dequeues the buf and creates an ATAPI command to perform the
482 * transfer in the buf.
483 * The bufs are queued by the strategy routine (wfdstrategy).
484 * Must be called at the correct (splbio) level.
485 */
486 static void wfd_start (struct wfd *t)
487 {
488 struct buf *bp = bufq_first(&t->buf_queue);
489 u_long blkno, nblk;
490 u_char op_code;
491 long count;
492 int pxcount, pxnblk;
493 u_char *pxdest;
494
495
496 /* See if there is a buf to do and we are not already doing one. */
497 if (! bp)
498 return;
499
500 /* Unqueue the request. */
501 bufq_remove(&t->buf_queue, bp);
502
503 /* Tell devstat we are starting on the transaction */
504 devstat_start_transaction(&t->device_stats);
505
506 /* We have a buf, now we should make a command
507 * First, translate the block to absolute and put it in terms of the
508 * logical blocksize of the device. */
509 blkno = bp->b_pblkno / (t->cap.sector_size / 512);
510 nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
511
512 if ((t->maxblks == 0) || (nblk <= t->maxblks)) {
513
514 if(bp->b_flags & B_READ) {
515 op_code = ATAPI_READ_BIG;
516 count = bp->b_bcount;
517 } else {
518 op_code = ATAPI_WRITE_BIG;
519 count = -bp->b_bcount;
520 }
521
522 /* only one transfer */
523 (int)bp->b_driver1 = 0;
524 (int)bp->b_driver2 = 0;
525 atapi_request_callback (t->ata, t->unit, op_code, 0,
526 blkno>>24, blkno>>16, blkno>>8, blkno,
527 0, nblk>>8, nblk, 0, 0,
528 0, 0, 0, 0, 0,
529 (u_char*) bp->b_data, count,
530 (void*)wfd_done, t, bp);
531 } else {
532
533 /*
534 * We can't handle this request in a single
535 * read/write operation. Instead, queue a set of
536 * transfers, and record the number of transfers
537 * and the running residual in the b_driver
538 * fields of the bp.
539 */
540
541 if(bp->b_flags & B_READ) {
542 op_code = ATAPI_READ_BIG;
543 } else {
544 op_code = ATAPI_WRITE_BIG;
545 }
546
547 /* calculate number of transfers */
548 (int)bp->b_driver1 = (nblk - 1) / t->maxblks;
549 (int)bp->b_driver2 = 0;
550
551 pxdest = (u_char *)bp->b_data;
552 pxcount = bp->b_bcount;
553
554 /* construct partial transfer requests */
555 while (nblk > 0) {
556 pxnblk = min(nblk, t->maxblks);
557 count = min(pxcount, t->maxblks * t->cap.sector_size);
558
559 atapi_request_callback(t->ata, t->unit, op_code, 0,
560 blkno>>24, blkno>>16, blkno>>8,
561 blkno, 0, pxnblk>>8, pxnblk,
562 0, 0, 0, 0, 0, 0, 0,
563 pxdest,
564 (bp->b_flags & B_READ) ?
565 count : -count,
566 (void*)wfd_done, t, bp);
567 nblk -= pxnblk;
568 pxcount -= count;
569 pxdest += count;
570 blkno += pxnblk;
571 }
572 }
573 }
574
575 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
576 struct atapires result)
577 {
578
579 if (result.code) {
580 wfd_error (t, result);
581 bp->b_error = EIO;
582 bp->b_flags |= B_ERROR;
583 } else
584 (int)bp->b_driver2 += resid;
585 /*
586 * We can't call biodone until all outstanding
587 * transfer fragments are handled. If one hits
588 * an error, we will be returning an error, but
589 * only when all are complete.
590 */
591 if (((int)bp->b_driver1)-- <= 0) {
592 bp->b_resid = (int)bp->b_driver2;
593
594 /* Tell devstat we have finished with the transaction */
595 devstat_end_transaction(&t->device_stats,
596 bp->b_bcount - bp->b_resid,
597 DEVSTAT_TAG_NONE,
598 (bp->b_flags & B_READ) ? DEVSTAT_READ : DEVSTAT_WRITE);
599
600 biodone (bp);
601 }
602
603 wfd_start (t);
604 }
605
606 static void wfd_error (struct wfd *t, struct atapires result)
607 {
608 if (result.code != RES_ERR)
609 return;
610 switch (result.error & AER_SKEY) {
611 case AER_SK_NOT_READY:
612 if (result.error & ~AER_SKEY) {
613 /* Not Ready */
614 printf ("wfd%d: not ready\n", t->lun);
615 return;
616 }
617 /* Tray open. */
618 if (! (t->flags & F_MEDIA_CHANGED))
619 printf ("wfd%d: tray open\n", t->lun);
620 t->flags |= F_MEDIA_CHANGED;
621 return;
622
623 case AER_SK_UNIT_ATTENTION:
624 /* Media changed. */
625 if (! (t->flags & F_MEDIA_CHANGED))
626 printf ("wfd%d: media changed\n", t->lun);
627 t->flags |= F_MEDIA_CHANGED;
628 return;
629
630 case AER_SK_ILLEGAL_REQUEST:
631 /* Unknown command or invalid command arguments. */
632 if (t->flags & F_DEBUG)
633 printf ("wfd%d: invalid command\n", t->lun);
634 return;
635 }
636 printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
637 result.status, ARS_BITS, result.error, AER_BITS);
638 }
639
640 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
641 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
642 u_char a9, char *addr, int count)
643 {
644 struct atapires result;
645
646 result = atapi_request_wait (t->ata, t->unit, cmd,
647 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
648 addr, count);
649 if (result.code) {
650 wfd_error (t, result);
651 return (EIO);
652 }
653 return (0);
654 }
655
656 /*
657 * Perform special action on behalf of the user.
658 * Knows about the internals of this device
659 */
660 int wfdioctl (dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
661 {
662 int lun = UNIT(dev);
663 struct wfd *t = wfdtab[lun];
664 int error = 0;
665
666 error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
667 wfdstrategy1, (ds_setgeom_t *)NULL);
668 if (error != ENOIOCTL)
669 return (error);
670
671 if (t->flags & F_MEDIA_CHANGED)
672 switch (cmd) {
673 case CDIOCSETDEBUG:
674 case CDIOCCLRDEBUG:
675 case CDIOCRESET:
676 /* These ops are media change transparent. */
677 break;
678 default:
679 /* Lock the media. */
680 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
681 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
682 break;
683 }
684 switch (cmd) {
685 case CDIOCSETDEBUG:
686 if (p->p_cred->pc_ucred->cr_uid)
687 return (EPERM);
688 t->flags |= F_DEBUG;
689 atapi_debug (t->ata, 1);
690 return 0;
691 case CDIOCCLRDEBUG:
692 if (p->p_cred->pc_ucred->cr_uid)
693 return (EPERM);
694 t->flags &= ~F_DEBUG;
695 atapi_debug (t->ata, 0);
696 return 0;
697 case CDIOCRESET:
698 if (p->p_cred->pc_ucred->cr_uid)
699 return (EPERM);
700 return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
701 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
702 case CDIOCEJECT:
703 /* Don't allow eject if the device is opened
704 * by somebody (not us) in block mode. */
705 if ((t->flags & F_BOPEN) && t->refcnt)
706 return (EBUSY);
707 return wfd_eject (t, 0);
708 case CDIOCCLOSE:
709 if ((t->flags & F_BOPEN) && t->refcnt)
710 return (0);
711 return wfd_eject (t, 1);
712 default:
713 return (ENOTTY);
714 }
715 return (error);
716 }
717
718 static int wfd_eject (struct wfd *t, int closeit)
719 {
720 struct atapires result;
721
722 /* Try to stop the disc. */
723 result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
724 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
725
726 if (result.code == RES_ERR &&
727 ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
728 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
729 int err;
730
731 if (!closeit)
732 return (0);
733 /*
734 * The disc was unloaded.
735 * Load it (close tray).
736 * Read the table of contents.
737 */
738 err = wfd_request_wait (t, ATAPI_START_STOP,
739 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
740 if (err)
741 return (err);
742
743 /* Lock the media. */
744 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
745 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
746
747 return (0);
748 }
749
750 if (result.code) {
751 wfd_error (t, result);
752 return (EIO);
753 }
754
755 if (closeit)
756 return (0);
757
758 /* Give it some time to stop spinning. */
759 tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
760 tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
761
762 /* Unlock. */
763 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
764 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
765
766 /* Eject. */
767 t->flags |= F_MEDIA_CHANGED;
768 return wfd_request_wait (t, ATAPI_START_STOP,
769 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
770 }
771
772 #ifdef WFD_MODULE
773 /*
774 * Loadable ATAPI Floppy driver stubs.
775 */
776 #include <sys/exec.h>
777 #include <sys/sysent.h>
778 #include <sys/lkm.h>
779
780 /*
781 * Construct lkm_dev structures (see lkm.h).
782 * Our bdevsw/cdevsw slot numbers are 19/69.
783 */
784
785
786 MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_cdevsw);
787 MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
788
789 /*
790 * Function called when loading the driver.
791 */
792 int wfd_load (struct lkm_table *lkmtp, int cmd)
793 {
794 struct atapi *ata;
795 int n, u;
796
797 if (! atapi_start)
798 /* No ATAPI driver available. */
799 return EPROTONOSUPPORT;
800 n = 0;
801 for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
802 if (ata->port)
803 for (u=0; u<2; ++u)
804 /* Probing controller ata->ctrlr, unit u. */
805 if (ata->params[u] && ! ata->attached[u] &&
806 wfdattach (ata, u, ata->params[u],
807 ata->debug) >= 0)
808 {
809 /* Drive found. */
810 ata->attached[u] = 1;
811 ++n;
812 }
813 if (! n)
814 /* No IDE Floppies found. */
815 return ENXIO;
816 return 0;
817 }
818
819 /*
820 * Function called when unloading the driver.
821 */
822 int wfd_unload (struct lkm_table *lkmtp, int cmd)
823 {
824 struct wfd **t;
825
826 for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
827 if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
828 /* The device is opened, cannot unload the driver. */
829 return EBUSY;
830 for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
831 (*t)->ata->attached[(*t)->unit] = 0;
832 free (*t, M_TEMP);
833 }
834 wfdnlun = 0;
835 bzero (wfdtab, sizeof(wfdtab));
836 return 0;
837 }
838
839 /*
840 * Dispatcher function for the module (load/unload/stat).
841 */
842 int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
843 {
844 int err = 0;
845
846 if (ver != LKM_VERSION)
847 return EINVAL;
848
849 if (cmd == LKM_E_LOAD)
850 err = wfd_load (lkmtp, cmd);
851 else if (cmd == LKM_E_UNLOAD)
852 err = wfd_unload (lkmtp, cmd);
853 if (err)
854 return err;
855
856 /* XXX Poking around in the LKM internals like this is bad.
857 */
858 /* Register the cdevsw entry. */
859 lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
860 err = lkmdispatch (lkmtp, cmd);
861 if (err)
862 return err;
863
864 /* Register the bdevsw entry. */
865 lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
866 return lkmdispatch (lkmtp, cmd);
867 }
868 #endif /* WFD_MODULE */
869
870 static wfd_devsw_installed = 0;
871
872 static void wfd_drvinit(void *unused)
873 {
874 if( ! wfd_devsw_installed ) {
875 cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_cdevsw);
876 wfd_devsw_installed = 1;
877 }
878 }
879
880 SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
881
882
883 #endif /* NWFD && NWDC && ATAPI */
Cache object: e1ef42ade6f18dd286a9afa136bc6149
|