]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ata/atapi-fd.c
This commit was generated by cvs2svn to compensate for changes in r103449,
[FreeBSD/FreeBSD.git] / sys / dev / 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$
29  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/ata.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/bio.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/disk.h>
40 #include <sys/devicestat.h>
41 #include <sys/cdio.h>
42 #include <machine/bus.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     bioq_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     fdp->dev->si_iosize_max = 256 * DEV_BSIZE;
111
112     afd_describe(fdp);
113     atadev->flags |= ATA_D_MEDIA_CHANGED;
114     atadev->driver = fdp;
115     return 1;
116 }
117
118 void
119 afddetach(struct ata_device *atadev)
120 {   
121     struct afd_softc *fdp = atadev->driver;
122     struct bio *bp;
123     
124     while ((bp = bioq_first(&fdp->queue))) {
125         bioq_remove(&fdp->queue, bp);
126         biofinish(bp, NULL, ENXIO);
127     }
128     disk_invalidate(&fdp->disk);
129     disk_destroy(fdp->dev);
130     devstat_remove_entry(&fdp->stats);
131     ata_free_name(atadev);
132     ata_free_lun(&afd_lun_map, fdp->lun);
133     free(fdp, M_AFD);
134     atadev->driver = NULL;
135 }   
136
137 static int 
138 afd_sense(struct afd_softc *fdp)
139 {
140     int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
141                        0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
142                        sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
143     int count, error = 0;
144
145     /* The IOMEGA Clik! doesn't support reading the cap page, fake it */
146     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
147         fdp->cap.transfer_rate = 500;
148         fdp->cap.heads = 1;
149         fdp->cap.sectors = 2;
150         fdp->cap.cylinders = 39441;
151         fdp->cap.sector_size = 512;
152         atapi_test_ready(fdp->device);
153         return 0;
154     }
155
156     /* get drive capabilities, some drives needs this repeated */
157     for (count = 0 ; count < 5 ; count++) {
158         if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
159                                       sizeof(struct afd_cappage),
160                                       ATPR_F_READ, 30, NULL, NULL)))
161             break;
162     }
163     if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
164         return 1;   
165     fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
166     fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
167     fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
168     return 0;
169 }
170
171 static void 
172 afd_describe(struct afd_softc *fdp)
173 {
174     if (bootverbose) {
175         ata_prtdev(fdp->device,
176                    "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
177                    fdp->device->param->model, fdp->device->param->revision,
178                    device_get_unit(fdp->device->channel->dev),
179                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave");
180         ata_prtdev(fdp->device,
181                    "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
182                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / 
183                    ((1024L * 1024L) / fdp->cap.sector_size),
184                    fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
185                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
186                    fdp->cap.sector_size);
187         ata_prtdev(fdp->device, "%dKB/s,", fdp->cap.transfer_rate / 8);
188         printf(" %s\n", ata_mode2str(fdp->device->mode));
189         if (fdp->cap.medium_type) {
190             ata_prtdev(fdp->device, "Medium: ");
191             switch (fdp->cap.medium_type) {
192             case MFD_2DD:
193                 printf("720KB DD disk"); break;
194
195             case MFD_HD_12:
196                 printf("1.2MB HD disk"); break;
197
198             case MFD_HD_144:
199                 printf("1.44MB HD disk"); break;
200
201             case MFD_UHD: 
202                 printf("120MB UHD disk"); break;
203
204             default:
205                 printf("Unknown (0x%x)", fdp->cap.medium_type);
206             }
207             if (fdp->cap.wp) printf(", writeprotected");
208         }
209         printf("\n");
210     }
211     else {
212         ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
213                    (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
214                    ((1024L * 1024L) / fdp->cap.sector_size),    
215                    fdp->device->param->model,
216                    fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
217                    device_get_unit(fdp->device->channel->dev),
218                    (fdp->device->unit == ATA_MASTER) ? "master" : "slave",
219                    ata_mode2str(fdp->device->mode));
220     }
221 }
222
223 static int
224 afdopen(dev_t dev, int flags, int fmt, struct thread *td)
225 {
226     struct afd_softc *fdp = dev->si_drv1;
227     struct disklabel *label = &fdp->disk.d_label;
228
229     atapi_test_ready(fdp->device);
230
231     if (count_dev(dev) == 1)
232         afd_prevent_allow(fdp, 1);
233
234     if (afd_sense(fdp))
235         ata_prtdev(fdp->device, "sense media type failed\n");
236
237     fdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
238
239     bzero(label, sizeof *label);
240     label->d_secsize = fdp->cap.sector_size;
241     label->d_nsectors = fdp->cap.sectors;  
242     label->d_ntracks = fdp->cap.heads;
243     label->d_ncylinders = fdp->cap.cylinders;
244     label->d_secpercyl = fdp->cap.sectors * fdp->cap.heads;
245     label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
246     return 0;
247 }
248
249 static int 
250 afdclose(dev_t dev, int flags, int fmt, struct thread *td)
251 {
252     struct afd_softc *fdp = dev->si_drv1;
253
254     if (count_dev(dev) == 1)
255         afd_prevent_allow(fdp, 0); 
256     return 0;
257 }
258
259 static int 
260 afdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
261 {
262     struct afd_softc *fdp = dev->si_drv1;
263
264     switch (cmd) {
265     case CDIOCEJECT:
266         if (count_dev(dev) > 1)
267             return EBUSY;
268         return afd_eject(fdp, 0);
269
270     case CDIOCCLOSE:
271         if (count_dev(dev) > 1)
272             return 0;
273         return afd_eject(fdp, 1);
274
275     default:
276         return ENOIOCTL;
277     }
278 }
279
280 static void 
281 afdstrategy(struct bio *bp)
282 {
283     struct afd_softc *fdp = bp->bio_dev->si_drv1;
284     int s;
285
286     if (fdp->device->flags & ATA_D_DETACHING) {
287         biofinish(bp, NULL, ENXIO);
288         return;
289     }
290
291     /* if it's a null transfer, return immediatly. */
292     if (bp->bio_bcount == 0) {
293         bp->bio_resid = 0;
294         biodone(bp);
295         return;
296     }
297
298     s = splbio();
299     bioqdisksort(&fdp->queue, bp);
300     splx(s);
301     ata_start(fdp->device->channel);
302 }
303
304 void 
305 afd_start(struct ata_device *atadev)
306 {
307     struct afd_softc *fdp = atadev->driver;
308     struct bio *bp = bioq_first(&fdp->queue);
309     u_int32_t lba;
310     u_int16_t count;
311     int8_t ccb[16];
312     caddr_t data_ptr;
313
314     if (!bp)
315         return;
316
317     bioq_remove(&fdp->queue, bp);
318
319     /* should reject all queued entries if media have changed. */
320     if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
321         biofinish(bp, NULL, EIO);
322         return;
323     }
324
325     lba = bp->bio_pblkno;
326     count = bp->bio_bcount / fdp->cap.sector_size;
327     data_ptr = bp->bio_data;
328     bp->bio_resid = bp->bio_bcount; 
329
330     bzero(ccb, sizeof(ccb));
331
332     if (bp->bio_cmd == BIO_READ)
333         ccb[0] = ATAPI_READ_BIG;
334     else
335         ccb[0] = ATAPI_WRITE_BIG;
336
337     ccb[2] = lba>>24;
338     ccb[3] = lba>>16;
339     ccb[4] = lba>>8;
340     ccb[5] = lba;
341     ccb[7] = count>>8;
342     ccb[8] = count;
343
344     devstat_start_transaction(&fdp->stats);
345
346     atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
347                     (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, 30,
348                     afd_done, bp);
349 }
350
351 static int 
352 afd_done(struct atapi_request *request)
353 {
354     struct bio *bp = request->driver;
355     struct afd_softc *fdp = request->device->driver;
356
357     if (request->error || (bp->bio_flags & BIO_ERROR)) {
358         bp->bio_error = request->error;
359         bp->bio_flags |= BIO_ERROR;
360     }
361     else
362         bp->bio_resid = bp->bio_bcount - request->donecount;
363     biofinish(bp, &fdp->stats, 0);
364     return 0;
365 }
366
367 static int 
368 afd_eject(struct afd_softc *fdp, int close)
369 {
370     int error;
371      
372     if ((error = afd_start_stop(fdp, 0)) == EBUSY) {
373         if (!close)
374             return 0;
375         if ((error = afd_start_stop(fdp, 3)))
376             return error;
377         return afd_prevent_allow(fdp, 1);
378     }
379     if (error)
380         return error;
381     if (close)
382         return 0;
383     if ((error = afd_prevent_allow(fdp, 0)))
384         return error;
385     fdp->device->flags |= ATA_D_MEDIA_CHANGED;
386     return afd_start_stop(fdp, 2);
387 }
388
389 static int
390 afd_start_stop(struct afd_softc *fdp, int start)
391 {
392     int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
393                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
394
395     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
396 }
397
398 static int
399 afd_prevent_allow(struct afd_softc *fdp, int lock)
400 {
401     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
402                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
403     
404     if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
405         return 0;
406     return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
407 }