Merge from vendor branch OPENSSL:
[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.12 2005/06/03 21:56:23 swildner 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     bufq_init(&fdp->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 buf *bp;
135     
136     while ((bp = bufq_first(&fdp->queue))) {
137         bufq_remove(&fdp->queue, bp);
138         bp->b_flags |= B_ERROR;
139         bp->b_error = ENXIO;
140         biodone(bp);
141     }
142     disk_invalidate(&fdp->disk);
143     disk_destroy(&fdp->disk);
144     devstat_remove_entry(&fdp->stats);
145     ata_free_name(atadev);
146     ata_free_lun(&afd_lun_map, fdp->lun);
147     free(fdp, M_AFD);
148     atadev->driver = NULL;
149 }   
150
151 static int 
152 afd_sense(struct afd_softc *fdp)
153 {
154     int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
155                        0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
156                        sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
157     int count, error = 0;
158
159     /* The IOMEGA Clik! doesn't support reading the cap page, fake it */
160     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
161         fdp->cap.transfer_rate = 500;
162         fdp->cap.heads = 1;
163         fdp->cap.sectors = 2;
164         fdp->cap.cylinders = 39441;
165         fdp->cap.sector_size = 512;
166         atapi_test_ready(fdp->device);
167         return 0;
168     }
169
170     /* get drive capabilities, some drives needs this repeated */
171     for (count = 0 ; count < 5 ; count++) {
172         if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
173                                       sizeof(struct afd_cappage),
174                                       ATPR_F_READ, 30, NULL, NULL)))
175             break;
176     }
177     if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
178         return 1;   
179     fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
180     fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
181     fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
182     return 0;
183 }
184
185 static void 
186 afd_describe(struct afd_softc *fdp)
187 {
188     if (bootverbose) {
189         ata_prtdev(fdp->device,
190                    "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
191                    fdp->device->param->model, fdp->device->param->revision,
192                    device_get_unit(fdp->device->channel->dev),
193                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave");
194         ata_prtdev(fdp->device,
195                    "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
196                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / 
197                    ((1024L * 1024L) / fdp->cap.sector_size),
198                    fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
199                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
200                    fdp->cap.sector_size);
201         ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8);
202         printf(" %s\n", ata_mode2str(fdp->device->mode));
203         if (fdp->cap.medium_type) {
204             ata_prtdev(fdp->device, "Medium: ");
205             switch (fdp->cap.medium_type) {
206             case MFD_2DD:
207                 printf("720KB DD disk"); break;
208
209             case MFD_HD_12:
210                 printf("1.2MB HD disk"); break;
211
212             case MFD_HD_144:
213                 printf("1.44MB HD disk"); break;
214
215             case MFD_UHD: 
216                 printf("120MB UHD disk"); break;
217
218             default:
219                 printf("Unknown (0x%x)", fdp->cap.medium_type);
220             }
221             if (fdp->cap.wp) printf(", writeprotected");
222         }
223         printf("\n");
224     }
225     else {
226         ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
227                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
228                    ((1024L * 1024L) / fdp->cap.sector_size),    
229                    fdp->device->param->model,
230                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
231                    device_get_unit(fdp->device->channel->dev),
232                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave",
233                    ata_mode2str(fdp->device->mode));
234     }
235 }
236
237 static int
238 afdopen(dev_t dev, int flags, int fmt, struct thread *td)
239 {
240     struct afd_softc *fdp = dev->si_drv1;
241     struct disklabel *label = &fdp->disk.d_label;
242
243     atapi_test_ready(fdp->device);
244
245     if (count_dev(dev) == 1)
246         afd_prevent_allow(fdp, 1);
247
248     if (afd_sense(fdp))
249         ata_prtdev(fdp->device, "sense media type failed\n");
250
251     fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
252
253     bzero(label, sizeof *label);
254     label->d_secsize = fdp->cap.sector_size;
255     label->d_nsectors = fdp->cap.sectors;  
256     label->d_ntracks = fdp->cap.heads;
257     label->d_ncylinders = fdp->cap.cylinders;
258     label->d_secpercyl = fdp->cap.sectors * fdp->cap.heads;
259     label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
260     return 0;
261 }
262
263 static int 
264 afdclose(dev_t dev, int flags, int fmt, struct thread *td)
265 {
266     struct afd_softc *fdp = dev->si_drv1;
267
268     if (count_dev(dev) == 1)
269         afd_prevent_allow(fdp, 0); 
270     return 0;
271 }
272
273 static int 
274 afdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
275 {
276     struct afd_softc *fdp = dev->si_drv1;
277
278     switch (cmd) {
279     case CDIOCEJECT:
280         if (count_dev(dev) > 1)
281             return EBUSY;
282         return afd_eject(fdp, 0);
283
284     case CDIOCCLOSE:
285         if (count_dev(dev) > 1)
286             return 0;
287         return afd_eject(fdp, 1);
288
289     default:
290         return ENOIOCTL;
291     }
292 }
293
294 static void 
295 afdstrategy(struct buf *bp)
296 {
297     struct afd_softc *fdp = bp->b_dev->si_drv1;
298
299     if (fdp->device->flags & ATA_D_DETACHING) {
300         bp->b_flags |= B_ERROR;
301         bp->b_error = ENXIO;
302         biodone(bp);
303         return;
304     }
305
306     /* if it's a null transfer, return immediatly. */
307     if (bp->b_bcount == 0) {
308         bp->b_resid = 0;
309         biodone(bp);
310         return;
311     }
312
313     crit_enter();
314     bufqdisksort(&fdp->queue, bp);
315     crit_exit();
316     ata_start(fdp->device->channel);
317 }
318
319 void 
320 afd_start(struct ata_device *atadev)
321 {
322     struct afd_softc *fdp = atadev->driver;
323     struct buf *bp = bufq_first(&fdp->queue);
324     u_int32_t lba;
325     u_int16_t count;
326     int8_t ccb[16];
327     caddr_t data_ptr;
328
329     if (!bp)
330         return;
331
332     bufq_remove(&fdp->queue, bp);
333
334     /* should reject all queued entries if media have changed. */
335     if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
336         bp->b_flags |= B_ERROR;
337         bp->b_error = EIO;
338         biodone(bp);
339         return;
340     }
341
342     lba = bp->b_pblkno;
343     count = bp->b_bcount / fdp->cap.sector_size;
344     data_ptr = bp->b_data;
345     bp->b_resid = bp->b_bcount; 
346
347     bzero(ccb, sizeof(ccb));
348
349     if (bp->b_flags & B_READ)
350         ccb[0] = ATAPI_READ_BIG;
351     else
352         ccb[0] = ATAPI_WRITE_BIG;
353
354     ccb[2] = lba>>24;
355     ccb[3] = lba>>16;
356     ccb[4] = lba>>8;
357     ccb[5] = lba;
358     ccb[7] = count>>8;
359     ccb[8] = count;
360
361     devstat_start_transaction(&fdp->stats);
362
363     atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
364                     (bp->b_flags & B_READ) ? ATPR_F_READ : 0, 30,
365                     afd_done, bp);
366 }
367
368 static int 
369 afd_done(struct atapi_request *request)
370 {
371     struct buf *bp = request->driver;
372     struct afd_softc *fdp = request->device->driver;
373
374     if (request->error || (bp->b_flags & B_ERROR)) {
375         bp->b_error = request->error;
376         bp->b_flags |= B_ERROR;
377     }
378     else
379         bp->b_resid = bp->b_bcount - request->donecount;
380     devstat_end_transaction_buf(&fdp->stats, bp);
381     biodone(bp);
382     return 0;
383 }
384
385 static int 
386 afd_eject(struct afd_softc *fdp, int close)
387 {
388     int error;
389      
390     if ((error = afd_start_stop(fdp, 0)) == EBUSY) {
391         if (!close)
392             return 0;
393         if ((error = afd_start_stop(fdp, 3)))
394             return error;
395         return afd_prevent_allow(fdp, 1);
396     }
397     if (error)
398         return error;
399     if (close)
400         return 0;
401     if ((error = afd_prevent_allow(fdp, 0)))
402         return error;
403     fdp->device->flags |= ATA_D_MEDIA_CHANGED;
404     return afd_start_stop(fdp, 2);
405 }
406
407 static int
408 afd_start_stop(struct afd_softc *fdp, int start)
409 {
410     int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
411                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
412
413     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
414 }
415
416 static int
417 afd_prevent_allow(struct afd_softc *fdp, int lock)
418 {
419     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
420                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
421     
422     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
423         return 0;
424     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
425 }