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.22 2008/01/06 16:55:49 swildner 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
);
88 fdp
->lun
= ata_get_lun(&afd_lun_map
);
89 ata_set_name(atadev
, "afd", fdp
->lun
);
90 bioq_init(&fdp
->bio_queue
);
97 devstat_add_entry(&fdp
->stats
, "afd", fdp
->lun
, DEV_BSIZE
,
98 DEVSTAT_NO_ORDERED_TAGS
,
99 DEVSTAT_TYPE_DIRECT
| DEVSTAT_TYPE_IF_IDE
,
100 DEVSTAT_PRIORITY_WFD
);
101 dev
= disk_create(fdp
->lun
, &fdp
->disk
, &afd_ops
);
105 if (!strncmp(atadev
->param
->model
, "IOMEGA ZIP", 10) ||
106 !strncmp(atadev
->param
->model
, "IOMEGA Clik!", 12))
107 fdp
->dev
->si_iosize_max
= 64 * DEV_BSIZE
;
109 fdp
->dev
->si_iosize_max
= 252 * DEV_BSIZE
;
112 atadev
->flags
|= ATA_D_MEDIA_CHANGED
;
113 atadev
->driver
= fdp
;
118 afddetach(struct ata_device
*atadev
)
120 struct afd_softc
*fdp
= atadev
->driver
;
124 while ((bio
= bioq_first(&fdp
->bio_queue
))) {
125 bioq_remove(&fdp
->bio_queue
, bio
);
127 bp
->b_flags
|= B_ERROR
;
131 disk_invalidate(&fdp
->disk
);
132 disk_destroy(&fdp
->disk
);
133 devstat_remove_entry(&fdp
->stats
);
134 ata_free_name(atadev
);
135 ata_free_lun(&afd_lun_map
, fdp
->lun
);
137 atadev
->driver
= NULL
;
141 afd_sense(struct afd_softc
*fdp
)
143 int8_t ccb
[16] = { ATAPI_MODE_SENSE_BIG
, 0, ATAPI_REWRITEABLE_CAP_PAGE
,
144 0, 0, 0, 0, sizeof(struct afd_cappage
) >> 8,
145 sizeof(struct afd_cappage
) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
146 int count
, error
= 0;
148 /* The IOMEGA Clik! doesn't support reading the cap page, fake it */
149 if (!strncmp(fdp
->device
->param
->model
, "IOMEGA Clik!", 12)) {
150 fdp
->cap
.transfer_rate
= 500;
152 fdp
->cap
.sectors
= 2;
153 fdp
->cap
.cylinders
= 39441;
154 fdp
->cap
.sector_size
= 512;
155 atapi_test_ready(fdp
->device
);
159 /* get drive capabilities, some drives needs this repeated */
160 for (count
= 0 ; count
< 5 ; count
++) {
161 if (!(error
= atapi_queue_cmd(fdp
->device
, ccb
, (caddr_t
)&fdp
->cap
,
162 sizeof(struct afd_cappage
),
163 ATPR_F_READ
, 30, NULL
, NULL
)))
166 if (error
|| fdp
->cap
.page_code
!= ATAPI_REWRITEABLE_CAP_PAGE
)
168 fdp
->cap
.cylinders
= ntohs(fdp
->cap
.cylinders
);
169 fdp
->cap
.sector_size
= ntohs(fdp
->cap
.sector_size
);
170 fdp
->cap
.transfer_rate
= ntohs(fdp
->cap
.transfer_rate
);
175 afd_describe(struct afd_softc
*fdp
)
178 ata_prtdev(fdp
->device
,
179 "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
180 fdp
->device
->param
->model
, fdp
->device
->param
->revision
,
181 device_get_unit(fdp
->device
->channel
->dev
),
182 (fdp
->device
->unit
== ATA_MASTER
) ? "master" : "slave");
183 ata_prtdev(fdp
->device
,
184 "%luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
185 (fdp
->cap
.cylinders
* fdp
->cap
.heads
* fdp
->cap
.sectors
) /
186 ((1024L * 1024L) / fdp
->cap
.sector_size
),
187 fdp
->cap
.cylinders
* fdp
->cap
.heads
* fdp
->cap
.sectors
,
188 fdp
->cap
.cylinders
, fdp
->cap
.heads
, fdp
->cap
.sectors
,
189 fdp
->cap
.sector_size
);
190 ata_prtdev(fdp
->device
, "%dKB/s,", fdp
->cap
.transfer_rate
/ 8);
191 kprintf(" %s\n", ata_mode2str(fdp
->device
->mode
));
192 if (fdp
->cap
.medium_type
) {
193 ata_prtdev(fdp
->device
, "Medium: ");
194 switch (fdp
->cap
.medium_type
) {
196 kprintf("720KB DD disk"); break;
199 kprintf("1.2MB HD disk"); break;
202 kprintf("1.44MB HD disk"); break;
205 kprintf("120MB UHD disk"); break;
208 kprintf("Unknown (0x%x)", fdp
->cap
.medium_type
);
210 if (fdp
->cap
.wp
) kprintf(", writeprotected");
215 ata_prtdev(fdp
->device
, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
216 (fdp
->cap
.cylinders
* fdp
->cap
.heads
* fdp
->cap
.sectors
) /
217 ((1024L * 1024L) / fdp
->cap
.sector_size
),
218 fdp
->device
->param
->model
,
219 fdp
->cap
.cylinders
, fdp
->cap
.heads
, fdp
->cap
.sectors
,
220 device_get_unit(fdp
->device
->channel
->dev
),
221 (fdp
->device
->unit
== ATA_MASTER
) ? "master" : "slave",
222 ata_mode2str(fdp
->device
->mode
));
227 afdopen(struct dev_open_args
*ap
)
229 cdev_t dev
= ap
->a_head
.a_dev
;
230 struct afd_softc
*fdp
= dev
->si_drv1
;
231 struct disk_info info
;
233 atapi_test_ready(fdp
->device
);
235 if (count_dev(dev
) == 1)
236 afd_prevent_allow(fdp
, 1);
239 ata_prtdev(fdp
->device
, "sense media type failed\n");
241 fdp
->device
->flags
&= ~ATA_D_MEDIA_CHANGED
;
243 bzero(&info
, sizeof(info
));
244 info
.d_media_blksize
= fdp
->cap
.sector_size
; /* mandatory */
245 info
.d_media_blocks
= fdp
->cap
.sectors
* fdp
->cap
.heads
*
248 info
.d_secpertrack
= fdp
->cap
.sectors
; /* optional */
249 info
.d_nheads
= fdp
->cap
.heads
;
250 info
.d_ncylinders
= fdp
->cap
.cylinders
;
251 info
.d_secpercyl
= fdp
->cap
.sectors
* fdp
->cap
.heads
;
253 disk_setdiskinfo(&fdp
->disk
, &info
);
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
);