Major BUF/BIO work commit. Make I/O BIO-centric and specify the disk or
[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.14 2006/03/24 18:35:30 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 cdevsw afd_cdevsw = {
58         /* name */      "afd",
59         /* maj */       118,
60         /* flags */     D_DISK | D_TRACKCLOSE,
61         /* port */      NULL,
62         /* clone */     NULL,
63
64         /* open */      afdopen,
65         /* close */     afdclose,
66         /* read */      physread,
67         /* write */     physwrite,
68         /* ioctl */     afdioctl,
69         /* poll */      nopoll,
70         /* mmap */      nommap,
71         /* strategy */  afdstrategy,
72         /* dump */      nodump,
73         /* psize */     nopsize
74 };
75
76 /* prototypes */
77 static int afd_sense(struct afd_softc *);
78 static void afd_describe(struct afd_softc *);
79 static int afd_done(struct atapi_request *);
80 static int afd_eject(struct afd_softc *, int);
81 static int afd_start_stop(struct afd_softc *, int);
82 static int afd_prevent_allow(struct afd_softc *, int);
83
84 /* internal vars */
85 static u_int32_t afd_lun_map = 0;
86 static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
87
88 int 
89 afdattach(struct ata_device *atadev)
90 {
91     struct afd_softc *fdp;
92     dev_t dev;
93
94     fdp = malloc(sizeof(struct afd_softc), M_AFD, M_WAITOK | M_ZERO);
95     if (!fdp) {
96         ata_prtdev(atadev, "out of memory\n");
97         return 0;
98     }
99
100     fdp->device = atadev;
101     fdp->lun = ata_get_lun(&afd_lun_map);
102     ata_set_name(atadev, "afd", fdp->lun);
103     bioq_init(&fdp->bio_queue);
104
105     if (afd_sense(fdp)) {
106         free(fdp, M_AFD);
107         return 0;
108     }
109
110     devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
111                       DEVSTAT_NO_ORDERED_TAGS,
112                       DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
113                       DEVSTAT_PRIORITY_WFD);
114     dev = disk_create(fdp->lun, &fdp->disk, 0, &afd_cdevsw);
115     dev->si_drv1 = fdp;
116     fdp->dev = dev;
117
118     if (!strncmp(atadev->param->model, "IOMEGA ZIP", 10) ||
119         !strncmp(atadev->param->model, "IOMEGA Clik!", 12))
120         fdp->dev->si_iosize_max = 64 * DEV_BSIZE;
121     else
122         fdp->dev->si_iosize_max = 252 * DEV_BSIZE;
123
124     afd_describe(fdp);
125     atadev->flags |= ATA_D_MEDIA_CHANGED;
126     atadev->driver = fdp;
127     return 1;
128 }
129
130 void
131 afddetach(struct ata_device *atadev)
132 {   
133     struct afd_softc *fdp = atadev->driver;
134     struct bio *bio;
135     struct buf *bp;
136     
137     while ((bio = bioq_first(&fdp->bio_queue))) {
138         bioq_remove(&fdp->bio_queue, bio);
139         bp = bio->bio_buf;
140         bp->b_flags |= B_ERROR;
141         bp->b_error = ENXIO;
142         biodone(bio);
143     }
144     disk_invalidate(&fdp->disk);
145     disk_destroy(&fdp->disk);
146     devstat_remove_entry(&fdp->stats);
147     ata_free_name(atadev);
148     ata_free_lun(&afd_lun_map, fdp->lun);
149     free(fdp, M_AFD);
150     atadev->driver = NULL;
151 }   
152
153 static int 
154 afd_sense(struct afd_softc *fdp)
155 {
156     int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
157                        0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
158                        sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
159     int count, error = 0;
160
161     /* The IOMEGA Clik! doesn't support reading the cap page, fake it */
162     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
163         fdp->cap.transfer_rate = 500;
164         fdp->cap.heads = 1;
165         fdp->cap.sectors = 2;
166         fdp->cap.cylinders = 39441;
167         fdp->cap.sector_size = 512;
168         atapi_test_ready(fdp->device);
169         return 0;
170     }
171
172     /* get drive capabilities, some drives needs this repeated */
173     for (count = 0 ; count < 5 ; count++) {
174         if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
175                                       sizeof(struct afd_cappage),
176                                       ATPR_F_READ, 30, NULL, NULL)))
177             break;
178     }
179     if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
180         return 1;   
181     fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
182     fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
183     fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
184     return 0;
185 }
186
187 static void 
188 afd_describe(struct afd_softc *fdp)
189 {
190     if (bootverbose) {
191         ata_prtdev(fdp->device,
192                    "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
193                    fdp->device->param->model, fdp->device->param->revision,
194                    device_get_unit(fdp->device->channel->dev),
195                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave");
196         ata_prtdev(fdp->device,
197                    "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
198                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / 
199                    ((1024L * 1024L) / fdp->cap.sector_size),
200                    fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
201                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
202                    fdp->cap.sector_size);
203         ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8);
204         printf(" %s\n", ata_mode2str(fdp->device->mode));
205         if (fdp->cap.medium_type) {
206             ata_prtdev(fdp->device, "Medium: ");
207             switch (fdp->cap.medium_type) {
208             case MFD_2DD:
209                 printf("720KB DD disk"); break;
210
211             case MFD_HD_12:
212                 printf("1.2MB HD disk"); break;
213
214             case MFD_HD_144:
215                 printf("1.44MB HD disk"); break;
216
217             case MFD_UHD: 
218                 printf("120MB UHD disk"); break;
219
220             default:
221                 printf("Unknown (0x%x)", fdp->cap.medium_type);
222             }
223             if (fdp->cap.wp) printf(", writeprotected");
224         }
225         printf("\n");
226     }
227     else {
228         ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
229                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
230                    ((1024L * 1024L) / fdp->cap.sector_size),    
231                    fdp->device->param->model,
232                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
233                    device_get_unit(fdp->device->channel->dev),
234                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave",
235                    ata_mode2str(fdp->device->mode));
236     }
237 }
238
239 static int
240 afdopen(dev_t dev, int flags, int fmt, struct thread *td)
241 {
242     struct afd_softc *fdp = dev->si_drv1;
243     struct disklabel *label = &fdp->disk.d_label;
244
245     atapi_test_ready(fdp->device);
246
247     if (count_dev(dev) == 1)
248         afd_prevent_allow(fdp, 1);
249
250     if (afd_sense(fdp))
251         ata_prtdev(fdp->device, "sense media type failed\n");
252
253     fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
254
255     bzero(label, sizeof *label);
256     label->d_secsize = fdp->cap.sector_size;
257     label->d_nsectors = fdp->cap.sectors;  
258     label->d_ntracks = fdp->cap.heads;
259     label->d_ncylinders = fdp->cap.cylinders;
260     label->d_secpercyl = fdp->cap.sectors * fdp->cap.heads;
261     label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
262     return 0;
263 }
264
265 static int 
266 afdclose(dev_t dev, int flags, int fmt, struct thread *td)
267 {
268     struct afd_softc *fdp = dev->si_drv1;
269
270     if (count_dev(dev) == 1)
271         afd_prevent_allow(fdp, 0); 
272     return 0;
273 }
274
275 static int 
276 afdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
277 {
278     struct afd_softc *fdp = dev->si_drv1;
279
280     switch (cmd) {
281     case CDIOCEJECT:
282         if (count_dev(dev) > 1)
283             return EBUSY;
284         return afd_eject(fdp, 0);
285
286     case CDIOCCLOSE:
287         if (count_dev(dev) > 1)
288             return 0;
289         return afd_eject(fdp, 1);
290
291     default:
292         return ENOIOCTL;
293     }
294 }
295
296 static void 
297 afdstrategy(dev_t dev, struct bio *bio)
298 {
299     struct buf *bp = bio->bio_buf;
300     struct afd_softc *fdp = dev->si_drv1;
301
302     if (fdp->device->flags & ATA_D_DETACHING) {
303         bp->b_flags |= B_ERROR;
304         bp->b_error = ENXIO;
305         biodone(bio);
306         return;
307     }
308
309     /* if it's a null transfer, return immediatly. */
310     if (bp->b_bcount == 0) {
311         bp->b_resid = 0;
312         biodone(bio);
313         return;
314     }
315
316     crit_enter();
317     bioqdisksort(&fdp->bio_queue, bio);
318     crit_exit();
319     ata_start(fdp->device->channel);
320 }
321
322 void 
323 afd_start(struct ata_device *atadev)
324 {
325     struct afd_softc *fdp = atadev->driver;
326     struct bio *bio = bioq_first(&fdp->bio_queue);
327     struct buf *bp;
328     u_int32_t lba;
329     u_int16_t count;
330     int8_t ccb[16];
331     caddr_t data_ptr;
332
333     if (bio == NULL)
334         return;
335
336     bioq_remove(&fdp->bio_queue, bio);
337     bp = bio->bio_buf;
338
339     /* should reject all queued entries if media have changed. */
340     if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
341         bp->b_flags |= B_ERROR;
342         bp->b_error = EIO;
343         biodone(bio);
344         return;
345     }
346
347     KKASSERT(bio->bio_offset % fdp->cap.sector_size == 0);
348
349     lba = bio->bio_offset / fdp->cap.sector_size;
350     count = bp->b_bcount / fdp->cap.sector_size;
351     data_ptr = bp->b_data;
352     bp->b_resid = bp->b_bcount; 
353
354     bzero(ccb, sizeof(ccb));
355
356     if (bp->b_flags & B_READ)
357         ccb[0] = ATAPI_READ_BIG;
358     else
359         ccb[0] = ATAPI_WRITE_BIG;
360
361     ccb[2] = lba>>24;
362     ccb[3] = lba>>16;
363     ccb[4] = lba>>8;
364     ccb[5] = lba;
365     ccb[7] = count>>8;
366     ccb[8] = count;
367
368     devstat_start_transaction(&fdp->stats);
369
370     atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
371                     (bp->b_flags & B_READ) ? ATPR_F_READ : 0, 30,
372                     afd_done, bio);
373 }
374
375 static int 
376 afd_done(struct atapi_request *request)
377 {
378     struct bio *bio = request->driver;
379     struct buf *bp = bio->bio_buf;
380     struct afd_softc *fdp = request->device->driver;
381
382     if (request->error || (bp->b_flags & B_ERROR)) {
383         bp->b_error = request->error;
384         bp->b_flags |= B_ERROR;
385     }
386     else
387         bp->b_resid = bp->b_bcount - request->donecount;
388     devstat_end_transaction_buf(&fdp->stats, bp);
389     biodone(bio);
390     return 0;
391 }
392
393 static int 
394 afd_eject(struct afd_softc *fdp, int close)
395 {
396     int error;
397      
398     if ((error = afd_start_stop(fdp, 0)) == EBUSY) {
399         if (!close)
400             return 0;
401         if ((error = afd_start_stop(fdp, 3)))
402             return error;
403         return afd_prevent_allow(fdp, 1);
404     }
405     if (error)
406         return error;
407     if (close)
408         return 0;
409     if ((error = afd_prevent_allow(fdp, 0)))
410         return error;
411     fdp->device->flags |= ATA_D_MEDIA_CHANGED;
412     return afd_start_stop(fdp, 2);
413 }
414
415 static int
416 afd_start_stop(struct afd_softc *fdp, int start)
417 {
418     int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
419                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
420
421     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
422 }
423
424 static int
425 afd_prevent_allow(struct afd_softc *fdp, int lock)
426 {
427     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
428                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
429     
430     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
431         return 0;
432     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
433 }