diff options
Diffstat (limited to 'sys/dev/ata/atapi-fd.c')
-rw-r--r-- | sys/dev/ata/atapi-fd.c | 198 |
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); } |