2 * Copyright (c) 1998,1999,2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
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.19 2006/10/25 20:55:53 dillon Exp $
32 #include <sys/param.h>
33 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
41 #include <sys/devicestat.h>
45 #include <sys/thread2.h>
48 #include "atapi-all.h"
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
;
57 static struct dev_ops afd_ops
= {
58 { "afd", 118, D_DISK
| D_TRACKCLOSE
},
64 .d_strategy
= afdstrategy
,
68 static int afd_sense(struct afd_softc
*);
69 static void afd_describe(struct afd_softc
*);
70 static int afd_done(struct atapi_request
*);
71 static int afd_eject(struct afd_softc
*, int);
72 static int afd_start_stop(struct afd_softc
*, int);
73 static int afd_prevent_allow(struct afd_softc
*, int);
76 static u_int32_t afd_lun_map
= 0;
77 static MALLOC_DEFINE(M_AFD
, "AFD driver", "ATAPI floppy driver buffers");
80 afdattach(struct ata_device
*atadev
)
82 struct afd_softc
*fdp
;
85 fdp
= kmalloc(sizeof(struct afd_softc
), M_AFD
, M_WAITOK
| M_ZERO
);
87 ata_prtdev(atadev
, "out of memory\n");
92 fdp
->lun
= ata_get_lun(&afd_lun_map
);
93 ata_set_name(atadev
, "afd", fdp
->lun
);
94 bioq_init(&fdp
->bio_queue
);
101 devstat_add_entry(&fdp
->stats
, "afd", fdp
->lun
, DEV_BSIZE
,
102 DEVSTAT_NO_ORDERED_TAGS
,
103 DEVSTAT_TYPE_DIRECT
| DEVSTAT_TYPE_IF_IDE
,
104 DEVSTAT_PRIORITY_WFD
);
105 dev
= disk_create(fdp
->lun
, &fdp
->disk
, 0, &afd_ops
);
109 if (!strncmp(atadev
->param
->model
, "IOMEGA ZIP", 10) ||
110 !strncmp(atadev
->param
->model
, "IOMEGA Clik!", 12))
111 fdp
->dev
->si_iosize_max
= 64 * DEV_BSIZE
;
113 fdp
->dev
->si_iosize_max
= 252 * DEV_BSIZE
;
116 atadev
->flags
|= ATA_D_MEDIA_CHANGED
;
117 atadev
->driver
= fdp
;
122 afddetach(struct ata_device
*atadev
)
124 struct afd_softc
*fdp
= atadev
->driver
;
128 while ((bio
= bioq_first(&fdp
->bio_queue
))) {
129 bioq_remove(&fdp
->bio_queue
, bio
);
131 bp
->b_flags
|= B_ERROR
;
135 disk_invalidate(&fdp
->disk
);
136 disk_destroy(&fdp
->disk
);
137 devstat_remove_entry(&fdp
->stats
);
138 ata_free_name(atadev
);
139 ata_free_lun(&afd_lun_map
, fdp
->lun
);
141 atadev
->driver
= NULL
;
145 afd_sense(struct afd_softc
*fdp
)
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;
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;
156 fdp
->cap
.sectors
= 2;
157 fdp
->cap
.cylinders
= 39441;
158 fdp
->cap
.sector_size
= 512;
159 atapi_test_ready(fdp
->device
);
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
)))
170 if (error
|| fdp
->cap
.page_code
!= ATAPI_REWRITEABLE_CAP_PAGE
)
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
);
179 afd_describe(struct afd_softc
*fdp
)
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
->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
) {
200 printf("720KB DD disk"); break;
203 printf("1.2MB HD disk"); break;
206 printf("1.44MB HD disk"); break;
209 printf("120MB UHD disk"); break;
212 printf("Unknown (0x%x)", fdp
->cap
.medium_type
);
214 if (fdp
->cap
.wp
) printf(", writeprotected");
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
));
231 afdopen(struct dev_open_args
*ap
)
233 cdev_t dev
= ap
->a_head
.a_dev
;
234 struct afd_softc
*fdp
= dev
->si_drv1
;
235 struct disklabel
*label
= &fdp
->disk
.d_label
;
237 atapi_test_ready(fdp
->device
);
239 if (count_dev(dev
) == 1)
240 afd_prevent_allow(fdp
, 1);
243 ata_prtdev(fdp
->device
, "sense media type failed\n");
245 fdp
->device
->flags
&= ~ATA_D_MEDIA_CHANGED
;
247 bzero(label
, sizeof *label
);
248 label
->d_secsize
= fdp
->cap
.sector_size
;
249 label
->d_nsectors
= fdp
->cap
.sectors
;
250 label
->d_ntracks
= fdp
->cap
.heads
;
251 label
->d_ncylinders
= fdp
->cap
.cylinders
;
252 label
->d_secpercyl
= fdp
->cap
.sectors
* fdp
->cap
.heads
;
253 label
->d_secperunit
= label
->d_secpercyl
* fdp
->cap
.cylinders
;
258 afdclose(struct dev_close_args
*ap
)
260 cdev_t dev
= ap
->a_head
.a_dev
;
261 struct afd_softc
*fdp
= dev
->si_drv1
;
263 if (count_dev(dev
) == 1)
264 afd_prevent_allow(fdp
, 0);
269 afdioctl(struct dev_ioctl_args
*ap
)
271 cdev_t dev
= ap
->a_head
.a_dev
;
272 struct afd_softc
*fdp
= dev
->si_drv1
;
276 if (count_dev(dev
) > 1)
278 return afd_eject(fdp
, 0);
281 if (count_dev(dev
) > 1)
283 return afd_eject(fdp
, 1);
291 afdstrategy(struct dev_strategy_args
*ap
)
293 cdev_t dev
= ap
->a_head
.a_dev
;
294 struct bio
*bio
= ap
->a_bio
;
295 struct buf
*bp
= bio
->bio_buf
;
296 struct afd_softc
*fdp
= dev
->si_drv1
;
298 if (fdp
->device
->flags
& ATA_D_DETACHING
) {
299 bp
->b_flags
|= B_ERROR
;
305 /* if it's a null transfer, return immediatly. */
306 if (bp
->b_bcount
== 0) {
313 bioqdisksort(&fdp
->bio_queue
, bio
);
315 ata_start(fdp
->device
->channel
);
320 afd_start(struct ata_device
*atadev
)
322 struct afd_softc
*fdp
= atadev
->driver
;
323 struct bio
*bio
= bioq_first(&fdp
->bio_queue
);
333 bioq_remove(&fdp
->bio_queue
, bio
);
336 /* should reject all queued entries if media have changed. */
337 if (fdp
->device
->flags
& ATA_D_MEDIA_CHANGED
) {
338 bp
->b_flags
|= B_ERROR
;
344 KKASSERT(bio
->bio_offset
% fdp
->cap
.sector_size
== 0);
346 lba
= bio
->bio_offset
/ fdp
->cap
.sector_size
;
347 count
= bp
->b_bcount
/ fdp
->cap
.sector_size
;
348 data_ptr
= bp
->b_data
;
349 bp
->b_resid
= bp
->b_bcount
;
351 bzero(ccb
, sizeof(ccb
));
353 if (bp
->b_cmd
== BUF_CMD_READ
)
354 ccb
[0] = ATAPI_READ_BIG
;
356 ccb
[0] = ATAPI_WRITE_BIG
;
365 devstat_start_transaction(&fdp
->stats
);
367 atapi_queue_cmd(fdp
->device
, ccb
, data_ptr
, count
* fdp
->cap
.sector_size
,
368 ((bp
->b_cmd
== BUF_CMD_READ
) ? ATPR_F_READ
: 0),
373 afd_done(struct atapi_request
*request
)
375 struct bio
*bio
= request
->driver
;
376 struct buf
*bp
= bio
->bio_buf
;
377 struct afd_softc
*fdp
= request
->device
->driver
;
379 if (request
->error
|| (bp
->b_flags
& B_ERROR
)) {
380 bp
->b_error
= request
->error
;
381 bp
->b_flags
|= B_ERROR
;
384 bp
->b_resid
= bp
->b_bcount
- request
->donecount
;
385 devstat_end_transaction_buf(&fdp
->stats
, bp
);
391 afd_eject(struct afd_softc
*fdp
, int close
)
395 if ((error
= afd_start_stop(fdp
, 0)) == EBUSY
) {
398 if ((error
= afd_start_stop(fdp
, 3)))
400 return afd_prevent_allow(fdp
, 1);
406 if ((error
= afd_prevent_allow(fdp
, 0)))
408 fdp
->device
->flags
|= ATA_D_MEDIA_CHANGED
;
409 return afd_start_stop(fdp
, 2);
413 afd_start_stop(struct afd_softc
*fdp
, int start
)
415 int8_t ccb
[16] = { ATAPI_START_STOP
, 0, 0, 0, start
,
416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
418 return atapi_queue_cmd(fdp
->device
, ccb
, NULL
, 0, 0, 30, NULL
, NULL
);
422 afd_prevent_allow(struct afd_softc
*fdp
, int lock
)
424 int8_t ccb
[16] = { ATAPI_PREVENT_ALLOW
, 0, 0, 0, lock
,
425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
427 if (!strncmp(fdp
->device
->param
->model
, "IOMEGA Clik!", 12))
429 return atapi_queue_cmd(fdp
->device
, ccb
, NULL
, 0, 0, 30, NULL
, NULL
);