MASSIVE reorganization of the device operations vector. Change cdevsw
[dragonfly.git] / sys / dev / disk / ata / atapi-fd.c
1 /*-
2  * Copyright (c) 1998,1999,2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
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,
10  *    without modification, immediately at the beginning of the file.
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  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/ata/atapi-fd.c,v 1.44.2.9 2002/07/31 11:19:26 sos Exp $
29  * $DragonFly: src/sys/dev/disk/ata/atapi-fd.c,v 1.16 2006/07/28 02:17:35 dillon Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/ata.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/buf.h>
38 #include <sys/bus.h>
39 #include <sys/conf.h>
40 #include <sys/disk.h>
41 #include <sys/devicestat.h>
42 #include <sys/cdio.h>
43 #include <machine/bus.h>
44 #include <sys/proc.h>
45 #include <sys/buf2.h>
46 #include <sys/thread2.h>
47 #include "ata-all.h"
48 #include "atapi-all.h"
49 #include "atapi-fd.h"
50
51 /* device structures */
52 static  d_open_t        afdopen;
53 static  d_close_t       afdclose;
54 static  d_ioctl_t       afdioctl;
55 static  d_strategy_t    afdstrategy;
56
57 static struct dev_ops afd_ops = {
58         { "afd", 118, D_DISK | D_TRACKCLOSE },
59         .d_open =       afdopen,
60         .d_close =      afdclose,
61         .d_read =       physread,
62         .d_write =      physwrite,
63         .d_ioctl =      afdioctl,
64         .d_strategy =   afdstrategy,
65 };
66
67 /* prototypes */
68 static int afd_sense(struct afd_softc *);
69 static void afd_describe(struct afd_softc *);
70 static int afd_done(struct atapi_request *);
71 static int afd_eject(struct afd_softc *, int);
72 static int afd_start_stop(struct afd_softc *, int);
73 static int afd_prevent_allow(struct afd_softc *, int);
74
75 /* internal vars */
76 static u_int32_t afd_lun_map = 0;
77 static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
78
79 int 
80 afdattach(struct ata_device *atadev)
81 {
82     struct afd_softc *fdp;
83     dev_t dev;
84
85     fdp = malloc(sizeof(struct afd_softc), M_AFD, M_WAITOK | M_ZERO);
86     if (!fdp) {
87         ata_prtdev(atadev, "out of memory\n");
88         return 0;
89     }
90
91     fdp->device = atadev;
92     fdp->lun = ata_get_lun(&afd_lun_map);
93     ata_set_name(atadev, "afd", fdp->lun);
94     bioq_init(&fdp->bio_queue);
95
96     if (afd_sense(fdp)) {
97         free(fdp, M_AFD);
98         return 0;
99     }
100
101     devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
102                       DEVSTAT_NO_ORDERED_TAGS,
103                       DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
104                       DEVSTAT_PRIORITY_WFD);
105     dev = disk_create(fdp->lun, &fdp->disk, 0, &afd_ops);
106     dev->si_drv1 = fdp;
107     fdp->dev = dev;
108
109     if (!strncmp(atadev->param->model, "IOMEGA ZIP", 10) ||
110         !strncmp(atadev->param->model, "IOMEGA Clik!", 12))
111         fdp->dev->si_iosize_max = 64 * DEV_BSIZE;
112     else
113         fdp->dev->si_iosize_max = 252 * DEV_BSIZE;
114
115     afd_describe(fdp);
116     atadev->flags |= ATA_D_MEDIA_CHANGED;
117     atadev->driver = fdp;
118     return 1;
119 }
120
121 void
122 afddetach(struct ata_device *atadev)
123 {   
124     struct afd_softc *fdp = atadev->driver;
125     struct bio *bio;
126     struct buf *bp;
127     
128     while ((bio = bioq_first(&fdp->bio_queue))) {
129         bioq_remove(&fdp->bio_queue, bio);
130         bp = bio->bio_buf;
131         bp->b_flags |= B_ERROR;
132         bp->b_error = ENXIO;
133         biodone(bio);
134     }
135     disk_invalidate(&fdp->disk);
136     disk_destroy(&fdp->disk);
137     devstat_remove_entry(&fdp->stats);
138     ata_free_name(atadev);
139     ata_free_lun(&afd_lun_map, fdp->lun);
140     free(fdp, M_AFD);
141     atadev->driver = NULL;
142 }   
143
144 static int 
145 afd_sense(struct afd_softc *fdp)
146 {
147     int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
148                        0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
149                        sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
150     int count, error = 0;
151
152     /* The IOMEGA Clik! doesn't support reading the cap page, fake it */
153     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
154         fdp->cap.transfer_rate = 500;
155         fdp->cap.heads = 1;
156         fdp->cap.sectors = 2;
157         fdp->cap.cylinders = 39441;
158         fdp->cap.sector_size = 512;
159         atapi_test_ready(fdp->device);
160         return 0;
161     }
162
163     /* get drive capabilities, some drives needs this repeated */
164     for (count = 0 ; count < 5 ; count++) {
165         if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
166                                       sizeof(struct afd_cappage),
167                                       ATPR_F_READ, 30, NULL, NULL)))
168             break;
169     }
170     if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
171         return 1;   
172     fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
173     fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
174     fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
175     return 0;
176 }
177
178 static void 
179 afd_describe(struct afd_softc *fdp)
180 {
181     if (bootverbose) {
182         ata_prtdev(fdp->device,
183                    "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
184                    fdp->device->param->model, fdp->device->param->revision,
185                    device_get_unit(fdp->device->channel->dev),
186                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave");
187         ata_prtdev(fdp->device,
188                    "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
189                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / 
190                    ((1024L * 1024L) / fdp->cap.sector_size),
191                    fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
192                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
193                    fdp->cap.sector_size);
194         ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8);
195         printf(" %s\n", ata_mode2str(fdp->device->mode));
196         if (fdp->cap.medium_type) {
197             ata_prtdev(fdp->device, "Medium: ");
198             switch (fdp->cap.medium_type) {
199             case MFD_2DD:
200                 printf("720KB DD disk"); break;
201
202             case MFD_HD_12:
203                 printf("1.2MB HD disk"); break;
204
205             case MFD_HD_144:
206                 printf("1.44MB HD disk"); break;
207
208             case MFD_UHD: 
209                 printf("120MB UHD disk"); break;
210
211             default:
212                 printf("Unknown (0x%x)", fdp->cap.medium_type);
213             }
214             if (fdp->cap.wp) printf(", writeprotected");
215         }
216         printf("\n");
217     }
218     else {
219         ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
220                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
221                    ((1024L * 1024L) / fdp->cap.sector_size),    
222                    fdp->device->param->model,
223                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
224                    device_get_unit(fdp->device->channel->dev),
225                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave",
226                    ata_mode2str(fdp->device->mode));
227     }
228 }
229
230 static int
231 afdopen(struct dev_open_args *ap)
232 {
233     dev_t dev = ap->a_head.a_dev;
234     struct afd_softc *fdp = dev->si_drv1;
235     struct disklabel *label = &fdp->disk.d_label;
236
237     atapi_test_ready(fdp->device);
238
239     if (count_dev(dev) == 1)
240         afd_prevent_allow(fdp, 1);
241
242     if (afd_sense(fdp))
243         ata_prtdev(fdp->device, "sense media type failed\n");
244
245     fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
246
247     bzero(label, sizeof *label);
248     label->d_secsize = fdp->cap.sector_size;
249     label->d_nsectors = fdp->cap.sectors;  
250     label->d_ntracks = fdp->cap.heads;
251     label->d_ncylinders = fdp->cap.cylinders;
252     label->d_secpercyl = fdp->cap.sectors * fdp->cap.heads;
253     label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
254     return 0;
255 }
256
257 static int 
258 afdclose(struct dev_close_args *ap)
259 {
260     dev_t dev = ap->a_head.a_dev;
261     struct afd_softc *fdp = dev->si_drv1;
262
263     if (count_dev(dev) == 1)
264         afd_prevent_allow(fdp, 0); 
265     return 0;
266 }
267
268 static int 
269 afdioctl(struct dev_ioctl_args *ap)
270 {
271     dev_t dev = ap->a_head.a_dev;
272     struct afd_softc *fdp = dev->si_drv1;
273
274     switch (ap->a_cmd) {
275     case CDIOCEJECT:
276         if (count_dev(dev) > 1)
277             return EBUSY;
278         return afd_eject(fdp, 0);
279
280     case CDIOCCLOSE:
281         if (count_dev(dev) > 1)
282             return 0;
283         return afd_eject(fdp, 1);
284
285     default:
286         return ENOIOCTL;
287     }
288 }
289
290 static int 
291 afdstrategy(struct dev_strategy_args *ap)
292 {
293     dev_t dev = ap->a_head.a_dev;
294     struct bio *bio = ap->a_bio;
295     struct buf *bp = bio->bio_buf;
296     struct afd_softc *fdp = dev->si_drv1;
297
298     if (fdp->device->flags & ATA_D_DETACHING) {
299         bp->b_flags |= B_ERROR;
300         bp->b_error = ENXIO;
301         biodone(bio);
302         return(0);
303     }
304
305     /* if it's a null transfer, return immediatly. */
306     if (bp->b_bcount == 0) {
307         bp->b_resid = 0;
308         biodone(bio);
309         return(0);
310     }
311
312     crit_enter();
313     bioqdisksort(&fdp->bio_queue, bio);
314     crit_exit();
315     ata_start(fdp->device->channel);
316     return(0);
317 }
318
319 void 
320 afd_start(struct ata_device *atadev)
321 {
322     struct afd_softc *fdp = atadev->driver;
323     struct bio *bio = bioq_first(&fdp->bio_queue);
324     struct buf *bp;
325     u_int32_t lba;
326     u_int16_t count;
327     int8_t ccb[16];
328     caddr_t data_ptr;
329
330     if (bio == NULL)
331         return;
332
333     bioq_remove(&fdp->bio_queue, bio);
334     bp = bio->bio_buf;
335
336     /* should reject all queued entries if media have changed. */
337     if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
338         bp->b_flags |= B_ERROR;
339         bp->b_error = EIO;
340         biodone(bio);
341         return;
342     }
343
344     KKASSERT(bio->bio_offset % fdp->cap.sector_size == 0);
345
346     lba = bio->bio_offset / fdp->cap.sector_size;
347     count = bp->b_bcount / fdp->cap.sector_size;
348     data_ptr = bp->b_data;
349     bp->b_resid = bp->b_bcount; 
350
351     bzero(ccb, sizeof(ccb));
352
353     if (bp->b_cmd == BUF_CMD_READ)
354         ccb[0] = ATAPI_READ_BIG;
355     else
356         ccb[0] = ATAPI_WRITE_BIG;
357
358     ccb[2] = lba>>24;
359     ccb[3] = lba>>16;
360     ccb[4] = lba>>8;
361     ccb[5] = lba;
362     ccb[7] = count>>8;
363     ccb[8] = count;
364
365     devstat_start_transaction(&fdp->stats);
366
367     atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
368                     ((bp->b_cmd == BUF_CMD_READ) ? ATPR_F_READ : 0),
369                     30, afd_done, bio);
370 }
371
372 static int 
373 afd_done(struct atapi_request *request)
374 {
375     struct bio *bio = request->driver;
376     struct buf *bp = bio->bio_buf;
377     struct afd_softc *fdp = request->device->driver;
378
379     if (request->error || (bp->b_flags & B_ERROR)) {
380         bp->b_error = request->error;
381         bp->b_flags |= B_ERROR;
382     }
383     else
384         bp->b_resid = bp->b_bcount - request->donecount;
385     devstat_end_transaction_buf(&fdp->stats, bp);
386     biodone(bio);
387     return 0;
388 }
389
390 static int 
391 afd_eject(struct afd_softc *fdp, int close)
392 {
393     int error;
394      
395     if ((error = afd_start_stop(fdp, 0)) == EBUSY) {
396         if (!close)
397             return 0;
398         if ((error = afd_start_stop(fdp, 3)))
399             return error;
400         return afd_prevent_allow(fdp, 1);
401     }
402     if (error)
403         return error;
404     if (close)
405         return 0;
406     if ((error = afd_prevent_allow(fdp, 0)))
407         return error;
408     fdp->device->flags |= ATA_D_MEDIA_CHANGED;
409     return afd_start_stop(fdp, 2);
410 }
411
412 static int
413 afd_start_stop(struct afd_softc *fdp, int start)
414 {
415     int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
416                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
417
418     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
419 }
420
421 static int
422 afd_prevent_allow(struct afd_softc *fdp, int lock)
423 {
424     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
425                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
426     
427     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
428         return 0;
429     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
430 }