summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/atapi-fd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata/atapi-fd.c')
-rw-r--r--sys/dev/ata/atapi-fd.c198
1 files changed, 128 insertions, 70 deletions
diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c
index 5772242..91c2111 100644
--- a/sys/dev/ata/atapi-fd.c
+++ b/sys/dev/ata/atapi-fd.c
@@ -37,79 +37,105 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/cdio.h>
+#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <geom/geom_disk.h>
#include <dev/ata/ata-all.h>
-#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-fd.h>
/* prototypes */
-static disk_open_t afdopen;
-static disk_close_t afdclose;
+static disk_open_t afd_open;
+static disk_close_t afd_close;
#ifdef notyet
-static disk_ioctl_t afdioctl;
+static disk_ioctl_t afd_ioctl;
#endif
-static disk_strategy_t afdstrategy;
+static disk_strategy_t afdstrategy;
+static void afd_detach(struct ata_device *atadev);
+static void afd_start(struct ata_device *atadev);
static int afd_sense(struct afd_softc *);
static void afd_describe(struct afd_softc *);
-static int afd_done(struct atapi_request *);
+static void afd_done(struct ata_request *);
static int afd_eject(struct afd_softc *, int);
static int afd_start_stop(struct afd_softc *, int);
static int afd_prevent_allow(struct afd_softc *, int);
+static int afd_test_ready(struct ata_device *atadev);
/* internal vars */
static u_int32_t afd_lun_map = 0;
static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
-int
-afdattach(struct ata_device *atadev)
+void
+afd_attach(struct ata_device *atadev)
{
struct afd_softc *fdp;
fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO);
if (!fdp) {
ata_prtdev(atadev, "out of memory\n");
- return 0;
+ return;
}
fdp->device = atadev;
fdp->lun = ata_get_lun(&afd_lun_map);
ata_set_name(atadev, "afd", fdp->lun);
bioq_init(&fdp->queue);
+ mtx_init(&fdp->queue_mtx, "ATAPI FD bioqueue lock", MTX_DEF, 0);
if (afd_sense(fdp)) {
free(fdp, M_AFD);
- return 0;
+ return;
}
- fdp->disk.d_open = afdopen;
- fdp->disk.d_close = afdclose;
+ /* use DMA if allowed and if drive/controller supports it */
+ if (atapi_dma && atadev->channel->dma &&
+ (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR)
+ atadev->setmode(atadev, ATA_DMA_MAX);
+ else
+ atadev->setmode(atadev, ATA_PIO_MAX);
+
+ /* setup the function ptrs */
+ atadev->detach = afd_detach;
+ atadev->start = afd_start;
+ atadev->softc = fdp;
+ atadev->flags |= ATA_D_MEDIA_CHANGED;
+
+ /* lets create the disk device */
+ fdp->disk.d_open = afd_open;
+ fdp->disk.d_close = afd_close;
#ifdef notyet
- fdp->disk.d_ioctl = afdioctl;
+ fdp->disk.d_ioctl = afd_ioctl;
#endif
fdp->disk.d_strategy = afdstrategy;
fdp->disk.d_name = "afd";
fdp->disk.d_drv1 = fdp;
- fdp->disk.d_maxsize = 256 * DEV_BSIZE;
- disk_create(fdp->lun, &fdp->disk, 0, NULL, NULL);
+ if (atadev->channel->dma)
+ fdp->disk.d_maxsize = atadev->channel->dma->max_iosize;
+ else
+ fdp->disk.d_maxsize = DFLTPHYS;
+ disk_create(fdp->lun, &fdp->disk, DISKFLAG_NOGIANT, NULL, NULL);
+ /* announce we are here */
afd_describe(fdp);
- atadev->flags |= ATA_D_MEDIA_CHANGED;
- atadev->driver = fdp;
- return 1;
}
-void
-afddetach(struct ata_device *atadev)
+static void
+afd_detach(struct ata_device *atadev)
{
- struct afd_softc *fdp = atadev->driver;
+ struct afd_softc *fdp = atadev->softc;
+ mtx_lock(&fdp->queue_mtx);
bioq_flush(&fdp->queue, NULL, ENXIO);
+ mtx_unlock(&fdp->queue_mtx);
disk_destroy(&fdp->disk);
+ ata_prtdev(atadev, "WARNING - removed from configuration\n");
ata_free_name(atadev);
ata_free_lun(&afd_lun_map, fdp->lun);
+ atadev->attach = NULL;
+ atadev->detach = NULL;
+ atadev->start = NULL;
+ atadev->softc = NULL;
+ atadev->flags = 0;
free(fdp, M_AFD);
- atadev->driver = NULL;
}
static int
@@ -118,7 +144,7 @@ afd_sense(struct afd_softc *fdp)
int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
- int count, error = 0;
+ int count;
/* The IOMEGA Clik! doesn't support reading the cap page, fake it */
if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
@@ -127,23 +153,22 @@ afd_sense(struct afd_softc *fdp)
fdp->cap.sectors = 2;
fdp->cap.cylinders = 39441;
fdp->cap.sector_size = 512;
- atapi_test_ready(fdp->device);
+ afd_test_ready(fdp->device);
return 0;
}
- /* get drive capabilities, some drives needs this repeated */
+ /* get drive capabilities, some bugridden drives needs this repeated */
for (count = 0 ; count < 5 ; count++) {
- if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
- sizeof(struct afd_cappage),
- ATPR_F_READ, 30, NULL, NULL)))
- break;
+ if (!ata_atapicmd(fdp->device, ccb, (caddr_t)&fdp->cap,
+ sizeof(struct afd_cappage), ATA_R_READ, 30) &&
+ fdp->cap.page_code == ATAPI_REWRITEABLE_CAP_PAGE) {
+ fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
+ fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
+ fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
+ return 0;
+ }
}
- if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
- return 1;
- fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
- fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
- fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
- return 0;
+ return 1;
}
static void
@@ -151,7 +176,7 @@ afd_describe(struct afd_softc *fdp)
{
if (bootverbose) {
ata_prtdev(fdp->device,
- "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
+ "<%.40s/%.8s> removable drive at ata%d as %s\n",
fdp->device->param->model, fdp->device->param->revision,
device_get_unit(fdp->device->channel->dev),
(fdp->device->unit == ATA_MASTER) ? "master" : "slave");
@@ -187,11 +212,8 @@ afd_describe(struct afd_softc *fdp)
}
}
else {
- ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
- (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
- ((1024L * 1024L) / fdp->cap.sector_size),
+ ata_prtdev(fdp->device, "REMOVABLE <%.40s> at ata%d-%s %s\n",
fdp->device->param->model,
- fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
device_get_unit(fdp->device->channel->dev),
(fdp->device->unit == ATA_MASTER) ? "master" : "slave",
ata_mode2str(fdp->device->mode));
@@ -199,15 +221,14 @@ afd_describe(struct afd_softc *fdp)
}
static int
-afdopen(struct disk *dp)
+afd_open(struct disk *dp)
{
struct afd_softc *fdp = dp->d_drv1;
- /* hold off access to we are fully attached */
- while (ata_delayed_attach)
- tsleep(&ata_delayed_attach, PRIBIO, "afdopn", 1);
+ if (fdp->device->flags & ATA_D_DETACHING)
+ return ENXIO;
- atapi_test_ready(fdp->device);
+ afd_test_ready(fdp->device);
afd_prevent_allow(fdp, 1);
@@ -226,7 +247,7 @@ afdopen(struct disk *dp)
}
static int
-afdclose(struct disk *dp)
+afd_close(struct disk *dp)
{
struct afd_softc *fdp = dp->d_drv1;
@@ -239,7 +260,7 @@ afdclose(struct disk *dp)
#ifdef notyet
static int
-afdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
+afd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
{
struct afd_softc *fdp = dp->d_drv1;
@@ -264,7 +285,6 @@ static void
afdstrategy(struct bio *bp)
{
struct afd_softc *fdp = bp->bio_disk->d_drv1;
- int s;
if (fdp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
@@ -278,26 +298,31 @@ afdstrategy(struct bio *bp)
return;
}
- s = splbio();
+ mtx_lock(&fdp->queue_mtx);
bioq_disksort(&fdp->queue, bp);
- splx(s);
+ mtx_unlock(&fdp->queue_mtx);
ata_start(fdp->device->channel);
}
-void
+static void
afd_start(struct ata_device *atadev)
{
- struct afd_softc *fdp = atadev->driver;
- struct bio *bp = bioq_first(&fdp->queue);
+ struct afd_softc *fdp = atadev->softc;
+ struct bio *bp;
+ struct ata_request *request;
u_int32_t lba;
u_int16_t count;
int8_t ccb[16];
- caddr_t data_ptr;
- if (!bp)
- return;
+ mtx_lock(&fdp->queue_mtx);
+ bp = bioq_first(&fdp->queue);
+ if (!bp) {
+ mtx_unlock(&fdp->queue_mtx);
+ return;
+ }
bioq_remove(&fdp->queue, bp);
+ mtx_unlock(&fdp->queue_mtx);
/* should reject all queued entries if media have changed. */
if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
@@ -307,7 +332,6 @@ afd_start(struct ata_device *atadev)
lba = bp->bio_pblkno;
count = bp->bio_bcount / fdp->cap.sector_size;
- data_ptr = bp->bio_data;
bp->bio_resid = bp->bio_bcount;
bzero(ccb, sizeof(ccb));
@@ -324,24 +348,49 @@ afd_start(struct ata_device *atadev)
ccb[7] = count>>8;
ccb[8] = count;
- atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
- (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, 30,
- afd_done, bp);
+ if (!(request = ata_alloc_request())) {
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ request->device = atadev;
+ request->driver = bp;
+ bcopy(ccb, request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 16 : 12);
+ request->data = bp->bio_data;
+ request->bytecount = count * fdp->cap.sector_size;
+ request->transfersize = min(request->bytecount, 65534);
+ request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30;
+ request->retries = 2;
+ request->callback = afd_done;
+ switch (bp->bio_cmd) {
+ case BIO_READ:
+ request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_READ);
+ break;
+ case BIO_WRITE:
+ request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_WRITE);
+ break;
+ default:
+ ata_prtdev(atadev, "unknown BIO operation\n");
+ ata_free_request(request);
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ ata_queue_request(request);
+
}
-static int
-afd_done(struct atapi_request *request)
+static void
+afd_done(struct ata_request *request)
{
struct bio *bp = request->driver;
- if (request->error || (bp->bio_flags & BIO_ERROR)) {
- bp->bio_error = request->error;
+ /* finish up transfer */
+ if ((bp->bio_error = request->result))
bp->bio_flags |= BIO_ERROR;
- }
- else
- bp->bio_resid = bp->bio_bcount - request->donecount;
+ bp->bio_resid = bp->bio_bcount - request->donecount;
biodone(bp);
- return 0;
+ ata_free_request(request);
}
static int
@@ -372,7 +421,7 @@ afd_start_stop(struct afd_softc *fdp, int start)
int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -383,5 +432,14 @@ afd_prevent_allow(struct afd_softc *fdp, int lock)
if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
return 0;
- return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30);
+}
+
+static int
+afd_test_ready(struct ata_device *atadev)
+{
+ int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
}
OpenPOWER on IntegriCloud