Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:28:22 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 <dev/ata/ata-all.h>
44 #include <dev/ata/atapi-all.h>
45 #include <dev/ata/atapi-fd.h>
46
47 /* device structures */
48 static  d_open_t        afdopen;
49 static  d_close_t       afdclose;
50 static  d_ioctl_t       afdioctl;
51 static  d_strategy_t    afdstrategy;
52 static struct cdevsw afd_cdevsw = {
53         /* open */      afdopen,
54         /* close */     afdclose,
55         /* read */      physread,
56         /* write */     physwrite,
57         /* ioctl */     afdioctl,
58         /* poll */      nopoll,
59         /* mmap */      nommap,
60         /* strategy */  afdstrategy,
61         /* name */      "afd",
62         /* maj */       118,
63         /* dump */      nodump,
64         /* psize */     nopsize,
65         /* flags */     D_DISK | D_TRACKCLOSE,
66 };
67 static struct cdevsw afddisk_cdevsw;
68
69 /* prototypes */
70 static int afd_sense(struct afd_softc *);
71 static void afd_describe(struct afd_softc *);
72 static int afd_done(struct atapi_request *);
73 static int afd_eject(struct afd_softc *, int);
74 static int afd_start_stop(struct afd_softc *, int);
75 static int afd_prevent_allow(struct afd_softc *, int);
76
77 /* internal vars */
78 static u_int32_t afd_lun_map = 0;
79 static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
80
81 int 
82 afdattach(struct ata_device *atadev)
83 {
84     struct afd_softc *fdp;
85     dev_t dev;
86
87     fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO);
88     if (!fdp) {
89         ata_prtdev(atadev, "out of memory\n");
90         return 0;
91     }
92
93     fdp->device = atadev;
94     fdp->lun = ata_get_lun(&afd_lun_map);
95     ata_set_name(atadev, "afd", fdp->lun);
96     bufq_init(&fdp->queue);
97
98     if (afd_sense(fdp)) {
99         free(fdp, M_AFD);
100         return 0;
101     }
102
103     devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
104                       DEVSTAT_NO_ORDERED_TAGS,
105                       DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
106                       DEVSTAT_PRIORITY_WFD);
107     dev = disk_create(fdp->lun, &fdp->disk, 0, &afd_cdevsw, &afddisk_cdevsw);
108     dev->si_drv1 = fdp;
109     fdp->dev = dev;
110
111     if (!strncmp(atadev->param->model, "IOMEGA ZIP", 10) ||
112         !strncmp(atadev->param->model, "IOMEGA Clik!", 12))
113         fdp->dev->si_iosize_max = 64 * DEV_BSIZE;
114     else
115         fdp->dev->si_iosize_max = 252 * DEV_BSIZE;
116
117     afd_describe(fdp);
118     atadev->flags |= ATA_D_MEDIA_CHANGED;
119     atadev->driver = fdp;
120     return 1;
121 }
122
123 void
124 afddetach(struct ata_device *atadev)
125 {   
126     struct afd_softc *fdp = atadev->driver;
127     struct buf *bp;
128     
129     while ((bp = bufq_first(&fdp->queue))) {
130         bufq_remove(&fdp->queue, bp);
131         bp->b_flags |= B_ERROR;
132         bp->b_error = ENXIO;
133         biodone(bp);
134     }
135     disk_invalidate(&fdp->disk);
136     disk_destroy(fdp->dev);
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->lun, 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(dev_t dev, int flags, int fmt, struct proc *p)
232 {
233     struct afd_softc *fdp = dev->si_drv1;
234     struct disklabel *label = &fdp->disk.d_label;
235
236     atapi_test_ready(fdp->device);
237
238     if (count_dev(dev) == 1)
239         afd_prevent_allow(fdp, 1);
240
241     if (afd_sense(fdp))
242         ata_prtdev(fdp->device, "sense media type failed\n");
243
244     fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
245
246     bzero(label, sizeof *label);
247     label->d_secsize = fdp->cap.sector_size;
248     label->d_nsectors = fdp->cap.sectors;  
249     label->d_ntracks = fdp->cap.heads;
250     label->d_ncylinders = fdp->cap.cylinders;
251     label->d_secpercyl = fdp->cap.sectors * fdp->cap.heads;
252     label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
253     return 0;
254 }
255
256 static int 
257 afdclose(dev_t dev, int flags, int fmt, struct proc *p)
258 {
259     struct afd_softc *fdp = dev->si_drv1;
260
261     if (count_dev(dev) == 1)
262         afd_prevent_allow(fdp, 0); 
263     return 0;
264 }
265
266 static int 
267 afdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
268 {
269     struct afd_softc *fdp = dev->si_drv1;
270
271     switch (cmd) {
272     case CDIOCEJECT:
273         if (count_dev(dev) > 1)
274             return EBUSY;
275         return afd_eject(fdp, 0);
276
277     case CDIOCCLOSE:
278         if (count_dev(dev) > 1)
279             return 0;
280         return afd_eject(fdp, 1);
281
282     default:
283         return ENOIOCTL;
284     }
285 }
286
287 static void 
288 afdstrategy(struct buf *bp)
289 {
290     struct afd_softc *fdp = bp->b_dev->si_drv1;
291     int s;
292
293     if (fdp->device->flags & ATA_D_DETACHING) {
294         bp->b_flags |= B_ERROR;
295         bp->b_error = ENXIO;
296         biodone(bp);
297         return;
298     }
299
300     /* if it's a null transfer, return immediatly. */
301     if (bp->b_bcount == 0) {
302         bp->b_resid = 0;
303         biodone(bp);
304         return;
305     }
306
307     s = splbio();
308     bufqdisksort(&fdp->queue, bp);
309     splx(s);
310     ata_start(fdp->device->channel);
311 }
312
313 void 
314 afd_start(struct ata_device *atadev)
315 {
316     struct afd_softc *fdp = atadev->driver;
317     struct buf *bp = bufq_first(&fdp->queue);
318     u_int32_t lba;
319     u_int16_t count;
320     int8_t ccb[16];
321     caddr_t data_ptr;
322
323     if (!bp)
324         return;
325
326     bufq_remove(&fdp->queue, bp);
327
328     /* should reject all queued entries if media have changed. */
329     if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
330         bp->b_flags |= B_ERROR;
331         bp->b_error = EIO;
332         biodone(bp);
333         return;
334     }
335
336     lba = bp->b_pblkno;
337     count = bp->b_bcount / fdp->cap.sector_size;
338     data_ptr = bp->b_data;
339     bp->b_resid = bp->b_bcount; 
340
341     bzero(ccb, sizeof(ccb));
342
343     if (bp->b_flags & B_READ)
344         ccb[0] = ATAPI_READ_BIG;
345     else
346         ccb[0] = ATAPI_WRITE_BIG;
347
348     ccb[2] = lba>>24;
349     ccb[3] = lba>>16;
350     ccb[4] = lba>>8;
351     ccb[5] = lba;
352     ccb[7] = count>>8;
353     ccb[8] = count;
354
355     devstat_start_transaction(&fdp->stats);
356
357     atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
358                     (bp->b_flags & B_READ) ? ATPR_F_READ : 0, 30,
359                     afd_done, bp);
360 }
361
362 static int 
363 afd_done(struct atapi_request *request)
364 {
365     struct buf *bp = request->driver;
366     struct afd_softc *fdp = request->device->driver;
367
368     if (request->error || (bp->b_flags & B_ERROR)) {
369         bp->b_error = request->error;
370         bp->b_flags |= B_ERROR;
371     }
372     else
373         bp->b_resid = bp->b_bcount - request->donecount;
374     devstat_end_transaction_buf(&fdp->stats, bp);
375     biodone(bp);
376     return 0;
377 }
378
379 static int 
380 afd_eject(struct afd_softc *fdp, int close)
381 {
382     int error;
383      
384     if ((error = afd_start_stop(fdp, 0)) == EBUSY) {
385         if (!close)
386             return 0;
387         if ((error = afd_start_stop(fdp, 3)))
388             return error;
389         return afd_prevent_allow(fdp, 1);
390     }
391     if (error)
392         return error;
393     if (close)
394         return 0;
395     if ((error = afd_prevent_allow(fdp, 0)))
396         return error;
397     fdp->device->flags |= ATA_D_MEDIA_CHANGED;
398     return afd_start_stop(fdp, 2);
399 }
400
401 static int
402 afd_start_stop(struct afd_softc *fdp, int start)
403 {
404     int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
405                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
406
407     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
408 }
409
410 static int
411 afd_prevent_allow(struct afd_softc *fdp, int lock)
412 {
413     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
414                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
415     
416     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
417         return 0;
418     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
419 }