2 * Copyright (c) 1997,1998 Junichi Satoh <junichi@astec.co.jp>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
26 * $FreeBSD: src/sys/i386/isa/wfd.c,v 1.35 2000/01/29 16:00:33 peter Exp $
27 * $DragonFly: src/sys/dev/disk/wfd/Attic/wfd.c,v 1.5 2003/07/21 05:50:40 dillon Exp $
31 * ATAPI Floppy, LS-120 driver
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
41 #include <sys/malloc.h>
43 #include <sys/devicestat.h>
44 #include <sys/disklabel.h>
45 #include <sys/diskslice.h>
48 #include <i386/isa/atapi.h>
50 static d_open_t wfdopen;
51 static d_close_t wfdclose;
52 static d_ioctl_t wfdioctl;
53 static d_strategy_t wfdstrategy;
55 static struct cdevsw wfd_cdevsw = {
57 /* maj */ WFD_CDEV_MAJOR,
65 /* write */ physwrite,
69 /* strategy */ wfdstrategy,
74 int wfdattach(struct atapi*, int, struct atapi_params*, int);
76 #define NUNIT (NWDC*2) /* Max. number of devices */
77 #define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
79 #define F_BOPEN 0x0001 /* The block device is opened */
80 #define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
81 #define F_DEBUG 0x0004 /* Print debug info */
84 * LS-120 Capabilities and Mechanical Status Page
87 /* Mode data header */
90 #define MDT_UNKNOWN 0x00
91 #define MDT_NO_DISC 0x70
92 #define MDT_DOOR_OPEN 0x71
93 #define MDT_FMT_ERROR 0x72
95 #define MDT_2DD_UN 0x10
97 #define MDT_2HD_UN 0x20
98 #define MDT_2HD_12_98 0x22
99 #define MDT_2HD_12 0x23
100 #define MDT_2HD_144 0x24
101 #define MDT_LS120 0x31
103 unsigned reserved0 :7;
104 unsigned wp :1; /* Write protect */
107 /* Capabilities page */
108 unsigned page_code :6; /* Page code - Should be 0x5 */
109 #define CAP_PAGE 0x05
110 unsigned reserved1_6 :1; /* Reserved */
111 unsigned ps :1; /* The device is capable of saving the page */
112 u_char page_length; /* Page Length - Should be 0x1e */
113 u_short transfer_rate; /* In kilobits per second */
114 u_char heads, sectors; /* Number of heads, Number of sectors per track */
115 u_short sector_size; /* Byes per sector */
116 u_short cyls; /* Number of cylinders */
117 u_char reserved10[10];
118 u_char motor_delay; /* Motor off delay */
119 u_char reserved21[7];
120 u_short rpm; /* Rotations per minute */
121 u_char reserved30[2];
125 struct atapi *ata; /* Controller structure */
126 int unit; /* IDE bus drive unit */
127 int lun; /* Logical device unit */
128 int flags; /* Device state flags */
129 int refcnt; /* The number of raw opens */
130 int maxblks; /* transfer size limit */
131 struct buf_queue_head buf_queue; /* Queue of i/o requests */
132 struct atapi_params *param; /* Drive parameters table */
133 struct cappage cap; /* Capabilities page info */
134 char description[80]; /* Device description */
135 struct diskslices *dk_slices; /* virtual drives */
137 struct devstat device_stats;
140 static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
141 static int wfdnlun = 0; /* Number of configured drives */
143 static void wfd_start (struct wfd *t);
144 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
145 struct atapires result);
146 static void wfd_error (struct wfd *t, struct atapires result);
147 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
148 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
149 u_char a9, char *addr, int count);
150 static void wfd_describe (struct wfd *t);
151 static int wfd_eject (struct wfd *t, int closeit);
154 * Dump the array in hexadecimal format for debugging purposes.
156 static void wfd_dump (int lun, char *label, void *data, int len)
160 printf ("wfd%d: %s %x", lun, label, *p++);
162 printf ("-%x", *p++);
167 wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
170 struct atapires result;
173 if (wfdnlun >= NUNIT) {
174 printf ("wfd: too many units\n");
177 if (!atapi_request_immediate) {
178 printf("wfd: configuration error, ATAPI core code not present!\n");
179 printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
182 t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
184 printf ("wfd: out of memory\n");
188 bzero (t, sizeof (struct wfd));
189 bufq_init(&t->buf_queue);
192 lun = t->lun = wfdnlun;
194 t->flags = F_MEDIA_CHANGED;
199 wfd_dump (t->lun, "info", ap, sizeof *ap);
202 /* Get drive capabilities. */
203 /* Do it twice to avoid the stale media changed state. */
204 for (i = 0; i < 2; i++) {
205 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
206 0, CAP_PAGE, 0, 0, 0, 0,
207 sizeof (t->cap) >> 8, sizeof (t->cap),
208 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
211 if (result.code == RES_ERR &&
212 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
213 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
214 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
215 sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
216 (char*) &t->cap, sizeof (t->cap));
218 /* Some drives have shorter capabilities page. */
219 if (result.code == RES_UNDERRUN)
222 if (result.code == 0) {
224 if (t->flags & F_DEBUG)
225 wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
230 * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least
231 * is known to lock up if transfers > 64 blocks are
234 if (!strcmp(ap->model, "IOMEGA ZIP 100 ATAPI")) {
235 printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n",
239 t->maxblks = 0; /* no limit */
244 make_dev(&wfd_cdevsw, dkmakeminor(t->lun, WHOLE_DISK_SLICE, RAW_PART),
245 UID_ROOT, GID_OPERATOR, 0640, "rwfd%d", t->lun);
248 * Export the drive to the devstat interface.
250 devstat_add_entry(&t->device_stats, "wfd",
251 t->lun, t->cap.sector_size,
252 DEVSTAT_NO_ORDERED_TAGS,
253 DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_IDE,
254 DEVSTAT_PRIORITY_WFD);
259 void wfd_describe (struct wfd *t)
263 t->cap.cyls = ntohs (t->cap.cyls);
264 t->cap.sector_size = ntohs (t->cap.sector_size);
266 printf ("wfd%d: ", t->lun);
267 switch (t->cap.medium_type) {
269 printf ("medium type unknown (no disk)");
273 printf ("2DD(capacity unknown) floppy disk loaded");
277 printf ("720KB floppy disk loaded");
280 printf ("2HD(capacity unknown) floppy disk loaded");
284 printf ("1.25MB(PC-9801 format) floppy disk loaded");
287 printf ("1.2MB floppy disk loaded");
290 printf ("1.44MB floppy disk loaded");
293 printf ("120MB floppy disk loaded");
296 printf ("no disc inside");
300 printf ("door open");
304 printf ("medium format error");
308 printf ("medium type=0x%x", t->cap.medium_type);
312 printf(", write protected");
316 printf ("wfd%d: ", t->lun);
317 printf ("%u cyls", t->cap.cyls);
318 printf (", %u heads, %u S/T", t->cap.heads, t->cap.sectors);
319 printf (", %u B/S", t->cap.sector_size);
324 int wfdopen (dev_t dev, int flags, int fmt, struct proc *p)
328 struct atapires result;
330 struct disklabel label;
332 /* Check that the device number is legal
333 * and the ATAPI driver is loaded. */
334 if (lun >= wfdnlun || ! atapi_request_immediate)
338 t->flags &= ~F_MEDIA_CHANGED;
339 /* Lock the media. */
340 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
341 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
343 /* Sense the media type */
344 result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
345 0, CAP_PAGE, 0, 0, 0, 0,
346 sizeof (t->cap) >> 8, sizeof (t->cap),
348 (char*) &t->cap, sizeof (t->cap));
350 printf ("wfd%d: Sense the media type is failed.\n", t->lun);
352 t->cap.cyls = ntohs (t->cap.cyls);
353 t->cap.sector_size = ntohs (t->cap.sector_size);
356 /* Build label for whole disk. */
357 bzero(&label, sizeof label);
358 label.d_secsize = t->cap.sector_size;
359 label.d_nsectors = t->cap.sectors;
360 label.d_ntracks = t->cap.heads;
361 label.d_ncylinders = t->cap.cyls;
362 label.d_secpercyl = t->cap.heads * t->cap.sectors;
364 label.d_secperunit = label.d_secpercyl * t->cap.cyls;
366 /* Initialize slice tables. */
367 errcode = dsopen(dev, fmt, 0, &t->dk_slices, &label);
376 * Close the device. Only called if we are the LAST
377 * occurence of an open device.
379 int wfdclose (dev_t dev, int flags, int fmt, struct proc *p)
382 struct wfd *t = wfdtab[lun];
384 dsclose(dev, fmt, t->dk_slices);
385 if(!dsisopen(t->dk_slices)) {
386 /* If we were the last open of the entire device, release it. */
388 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
390 t->flags &= ~F_BOPEN;
396 * Actually translate the requested transfer into one the physical driver can
397 * understand. The transfer is described by a buf and will include only one
400 void wfdstrategy (struct buf *bp)
402 int lun = UNIT(bp->b_dev);
403 struct wfd *t = wfdtab[lun];
406 /* If it's a null transfer, return immediatly. */
407 if (bp->b_bcount == 0) {
414 * Do bounds checking, adjust transfer, and set b_pblkno.
416 if (dscheck(bp, t->dk_slices) <= 0) {
423 /* Place it in the queue of disk activities for this disk. */
424 bufqdisksort (&t->buf_queue, bp);
426 /* Tell the device to get going on the transfer if it's
427 * not doing anything, otherwise just wait for completion. */
433 * Look to see if there is a buf waiting for the device
434 * and that the device is not already busy. If both are true,
435 * It dequeues the buf and creates an ATAPI command to perform the
436 * transfer in the buf.
437 * The bufs are queued by the strategy routine (wfdstrategy).
438 * Must be called at the correct (splbio) level.
440 static void wfd_start (struct wfd *t)
442 struct buf *bp = bufq_first(&t->buf_queue);
450 /* See if there is a buf to do and we are not already doing one. */
454 /* Unqueue the request. */
455 bufq_remove(&t->buf_queue, bp);
457 /* Tell devstat we are starting on the transaction */
458 devstat_start_transaction(&t->device_stats);
460 /* We have a buf, now we should make a command
461 * First, translate the block to absolute and put it in terms of the
462 * logical blocksize of the device. */
463 blkno = bp->b_pblkno / (t->cap.sector_size / 512);
464 nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
466 if ((t->maxblks == 0) || (nblk <= t->maxblks)) {
468 if(bp->b_flags & B_READ) {
469 op_code = ATAPI_READ_BIG;
470 count = bp->b_bcount;
472 op_code = ATAPI_WRITE_BIG;
473 count = -bp->b_bcount;
476 /* only one transfer */
477 (int)bp->b_driver1 = 0;
478 (int)bp->b_driver2 = 0;
479 atapi_request_callback (t->ata, t->unit, op_code, 0,
480 blkno>>24, blkno>>16, blkno>>8, blkno,
481 0, nblk>>8, nblk, 0, 0,
483 (u_char*) bp->b_data, count,
484 (void*)wfd_done, t, bp);
488 * We can't handle this request in a single
489 * read/write operation. Instead, queue a set of
490 * transfers, and record the number of transfers
491 * and the running residual in the b_driver
495 if(bp->b_flags & B_READ) {
496 op_code = ATAPI_READ_BIG;
498 op_code = ATAPI_WRITE_BIG;
501 /* calculate number of transfers */
502 (int)bp->b_driver1 = (nblk - 1) / t->maxblks;
503 (int)bp->b_driver2 = 0;
505 pxdest = (u_char *)bp->b_data;
506 pxcount = bp->b_bcount;
508 /* construct partial transfer requests */
510 pxnblk = min(nblk, t->maxblks);
511 count = min(pxcount, t->maxblks * t->cap.sector_size);
513 atapi_request_callback(t->ata, t->unit, op_code, 0,
514 blkno>>24, blkno>>16, blkno>>8,
515 blkno, 0, pxnblk>>8, pxnblk,
518 (bp->b_flags & B_READ) ?
520 (void*)wfd_done, t, bp);
529 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
530 struct atapires result)
534 wfd_error (t, result);
536 bp->b_flags |= B_ERROR;
538 (int)bp->b_driver2 += resid;
540 * We can't call biodone until all outstanding
541 * transfer fragments are handled. If one hits
542 * an error, we will be returning an error, but
543 * only when all are complete.
545 if (((int)bp->b_driver1)-- <= 0) {
546 bp->b_resid = (int)bp->b_driver2;
547 devstat_end_transaction_buf(&t->device_stats, bp);
554 static void wfd_error (struct wfd *t, struct atapires result)
556 if (result.code != RES_ERR)
558 switch (result.error & AER_SKEY) {
559 case AER_SK_NOT_READY:
560 if (result.error & ~AER_SKEY) {
562 printf ("wfd%d: not ready\n", t->lun);
566 if (! (t->flags & F_MEDIA_CHANGED))
567 printf ("wfd%d: tray open\n", t->lun);
568 t->flags |= F_MEDIA_CHANGED;
571 case AER_SK_UNIT_ATTENTION:
573 if (! (t->flags & F_MEDIA_CHANGED))
574 printf ("wfd%d: media changed\n", t->lun);
575 t->flags |= F_MEDIA_CHANGED;
578 case AER_SK_ILLEGAL_REQUEST:
579 /* Unknown command or invalid command arguments. */
580 if (t->flags & F_DEBUG)
581 printf ("wfd%d: invalid command\n", t->lun);
584 printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
585 result.status, ARS_BITS, result.error, AER_BITS);
588 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
589 u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
590 u_char a9, char *addr, int count)
592 struct atapires result;
594 result = atapi_request_wait (t->ata, t->unit, cmd,
595 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
598 wfd_error (t, result);
605 * Perform special action on behalf of the user.
606 * Knows about the internals of this device
608 int wfdioctl (dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
611 struct wfd *t = wfdtab[lun];
614 error = dsioctl(dev, cmd, addr, flag, &t->dk_slices);
615 if (error != ENOIOCTL)
618 if (t->flags & F_MEDIA_CHANGED)
623 /* These ops are media change transparent. */
626 /* Lock the media. */
627 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
628 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
637 atapi_debug (t->ata, 1);
643 t->flags &= ~F_DEBUG;
644 atapi_debug (t->ata, 0);
650 return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
651 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
653 /* Don't allow eject if the device is opened
654 * by somebody (not us) in block mode. */
655 if ((t->flags & F_BOPEN) && t->refcnt)
657 return wfd_eject (t, 0);
659 if ((t->flags & F_BOPEN) && t->refcnt)
661 return wfd_eject (t, 1);
668 static int wfd_eject (struct wfd *t, int closeit)
670 struct atapires result;
672 /* Try to stop the disc. */
673 result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
674 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
676 if (result.code == RES_ERR &&
677 ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
678 (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
684 * The disc was unloaded.
685 * Load it (close tray).
686 * Read the table of contents.
688 err = wfd_request_wait (t, ATAPI_START_STOP,
689 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
693 /* Lock the media. */
694 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
695 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
701 wfd_error (t, result);
708 /* Give it some time to stop spinning. */
709 tsleep ((caddr_t)&lbolt, 0, "wfdej1", 0);
710 tsleep ((caddr_t)&lbolt, 0, "wfdej2", 0);
713 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
714 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
717 t->flags |= F_MEDIA_CHANGED;
718 return wfd_request_wait (t, ATAPI_START_STOP,
719 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
722 static void wfd_drvinit(void *unused)
724 cdevsw_add(&wfd_cdevsw);
727 SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)