Merge from vendor branch NTPD:
[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.11 2004/05/13 23:49:14 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 "ata-all.h"
47 #include "atapi-all.h"
48 #include "atapi-fd.h"
49
50 /* device structures */
51 static  d_open_t        afdopen;
52 static  d_close_t       afdclose;
53 static  d_ioctl_t       afdioctl;
54 static  d_strategy_t    afdstrategy;
55
56 static struct cdevsw afd_cdevsw = {
57         /* name */      "afd",
58         /* maj */       118,
59         /* flags */     D_DISK | D_TRACKCLOSE,
60         /* port */      NULL,
61         /* clone */     NULL,
62
63         /* open */      afdopen,
64         /* close */     afdclose,
65         /* read */      physread,
66         /* write */     physwrite,
67         /* ioctl */     afdioctl,
68         /* poll */      nopoll,
69         /* mmap */      nommap,
70         /* strategy */  afdstrategy,
71         /* dump */      nodump,
72         /* psize */     nopsize
73 };
74
75 /* prototypes */
76 static int afd_sense(struct afd_softc *);
77 static void afd_describe(struct afd_softc *);
78 static int afd_done(struct atapi_request *);
79 static int afd_eject(struct afd_softc *, int);
80 static int afd_start_stop(struct afd_softc *, int);
81 static int afd_prevent_allow(struct afd_softc *, int);
82
83 /* internal vars */
84 static u_int32_t afd_lun_map = 0;
85 static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
86
87 int 
88 afdattach(struct ata_device *atadev)
89 {
90     struct afd_softc *fdp;
91     dev_t dev;
92
93     fdp = malloc(sizeof(struct afd_softc), M_AFD, M_WAITOK | M_ZERO);
94     if (!fdp) {
95         ata_prtdev(atadev, "out of memory\n");
96         return 0;
97     }
98
99     fdp->device = atadev;
100     fdp->lun = ata_get_lun(&afd_lun_map);
101     ata_set_name(atadev, "afd", fdp->lun);
102     bufq_init(&fdp->queue);
103
104     if (afd_sense(fdp)) {
105         free(fdp, M_AFD);
106         return 0;
107     }
108
109     devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
110                       DEVSTAT_NO_ORDERED_TAGS,
111                       DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
112                       DEVSTAT_PRIORITY_WFD);
113     dev = disk_create(fdp->lun, &fdp->disk, 0, &afd_cdevsw);
114     dev->si_drv1 = fdp;
115     fdp->dev = dev;
116
117     if (!strncmp(atadev->param->model, "IOMEGA ZIP", 10) ||
118         !strncmp(atadev->param->model, "IOMEGA Clik!", 12))
119         fdp->dev->si_iosize_max = 64 * DEV_BSIZE;
120     else
121         fdp->dev->si_iosize_max = 252 * DEV_BSIZE;
122
123     afd_describe(fdp);
124     atadev->flags |= ATA_D_MEDIA_CHANGED;
125     atadev->driver = fdp;
126     return 1;
127 }
128
129 void
130 afddetach(struct ata_device *atadev)
131 {   
132     struct afd_softc *fdp = atadev->driver;
133     struct buf *bp;
134     
135     while ((bp = bufq_first(&fdp->queue))) {
136         bufq_remove(&fdp->queue, bp);
137         bp->b_flags |= B_ERROR;
138         bp->b_error = ENXIO;
139         biodone(bp);
140     }
141     disk_invalidate(&fdp->disk);
142     disk_destroy(&fdp->disk);
143     devstat_remove_entry(&fdp->stats);
144     ata_free_name(atadev);
145     ata_free_lun(&afd_lun_map, fdp->lun);
146     free(fdp, M_AFD);
147     atadev->driver = NULL;
148 }   
149
150 static int 
151 afd_sense(struct afd_softc *fdp)
152 {
153     int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
154                        0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
155                        sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
156     int count, error = 0;
157
158     /* The IOMEGA Clik! doesn't support reading the cap page, fake it */
159     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
160         fdp->cap.transfer_rate = 500;
161         fdp->cap.heads = 1;
162         fdp->cap.sectors = 2;
163         fdp->cap.cylinders = 39441;
164         fdp->cap.sector_size = 512;
165         atapi_test_ready(fdp->device);
166         return 0;
167     }
168
169     /* get drive capabilities, some drives needs this repeated */
170     for (count = 0 ; count < 5 ; count++) {
171         if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
172                                       sizeof(struct afd_cappage),
173                                       ATPR_F_READ, 30, NULL, NULL)))
174             break;
175     }
176     if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
177         return 1;   
178     fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
179     fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
180     fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
181     return 0;
182 }
183
184 static void 
185 afd_describe(struct afd_softc *fdp)
186 {
187     if (bootverbose) {
188         ata_prtdev(fdp->device,
189                    "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
190                    fdp->device->param->model, fdp->device->param->revision,
191                    device_get_unit(fdp->device->channel->dev),
192                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave");
193         ata_prtdev(fdp->device,
194                    "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
195                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / 
196                    ((1024L * 1024L) / fdp->cap.sector_size),
197                    fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
198                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
199                    fdp->cap.sector_size);
200         ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8);
201         printf(" %s\n", ata_mode2str(fdp->device->mode));
202         if (fdp->cap.medium_type) {
203             ata_prtdev(fdp->device, "Medium: ");
204             switch (fdp->cap.medium_type) {
205             case MFD_2DD:
206                 printf("720KB DD disk"); break;
207
208             case MFD_HD_12:
209                 printf("1.2MB HD disk"); break;
210
211             case MFD_HD_144:
212                 printf("1.44MB HD disk"); break;
213
214             case MFD_UHD: 
215                 printf("120MB UHD disk"); break;
216
217             default:
218                 printf("Unknown (0x%x)", fdp->cap.medium_type);
219             }
220             if (fdp->cap.wp) printf(", writeprotected");
221         }
222         printf("\n");
223     }
224     else {
225         ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
226                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
227                    ((1024L * 1024L) / fdp->cap.sector_size),    
228                    fdp->device->param->model,
229                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
230                    device_get_unit(fdp->device->channel->dev),
231                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave",
232                    ata_mode2str(fdp->device->mode));
233     }
234 }
235
236 static int
237 afdopen(dev_t dev, int flags, int fmt, struct thread *td)
238 {
239     struct afd_softc *fdp = dev->si_drv1;
240     struct disklabel *label = &fdp->disk.d_label;
241
242     atapi_test_ready(fdp->device);
243
244     if (count_dev(dev) == 1)
245         afd_prevent_allow(fdp, 1);
246
247     if (afd_sense(fdp))
248         ata_prtdev(fdp->device, "sense media type failed\n");
249
250     fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
251
252     bzero(label, sizeof *label);
253     label->d_secsize = fdp->cap.sector_size;
254     label->d_nsectors = fdp->cap.sectors;  
255     label->d_ntracks = fdp->cap.heads;
256     label->d_ncylinders = fdp->cap.cylinders;
257     label->d_secpercyl = fdp->cap.sectors * fdp->cap.heads;
258     label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
259     return 0;
260 }
261
262 static int 
263 afdclose(dev_t dev, int flags, int fmt, struct thread *td)
264 {
265     struct afd_softc *fdp = dev->si_drv1;
266
267     if (count_dev(dev) == 1)
268         afd_prevent_allow(fdp, 0); 
269     return 0;
270 }
271
272 static int 
273 afdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
274 {
275     struct afd_softc *fdp = dev->si_drv1;
276
277     switch (cmd) {
278     case CDIOCEJECT:
279         if (count_dev(dev) > 1)
280             return EBUSY;
281         return afd_eject(fdp, 0);
282
283     case CDIOCCLOSE:
284         if (count_dev(dev) > 1)
285             return 0;
286         return afd_eject(fdp, 1);
287
288     default:
289         return ENOIOCTL;
290     }
291 }
292
293 static void 
294 afdstrategy(struct buf *bp)
295 {
296     struct afd_softc *fdp = bp->b_dev->si_drv1;
297     int s;
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     s = splbio();
314     bufqdisksort(&fdp->queue, bp);
315     splx(s);
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 }