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