144454Ssos/*- 2178067Ssos * Copyright (c) 1998 - 2008 S�ren Schmidt <sos@FreeBSD.org> 344454Ssos * All rights reserved. 444454Ssos * 544454Ssos * Redistribution and use in source and binary forms, with or without 644454Ssos * modification, are permitted provided that the following conditions 744454Ssos * are met: 844454Ssos * 1. Redistributions of source code must retain the above copyright 944454Ssos * notice, this list of conditions and the following disclaimer, 1044454Ssos * without modification, immediately at the beginning of the file. 1144454Ssos * 2. Redistributions in binary form must reproduce the above copyright 1244454Ssos * notice, this list of conditions and the following disclaimer in the 1344454Ssos * documentation and/or other materials provided with the distribution. 1444454Ssos * 1544454Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1644454Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1744454Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1844454Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1944454Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2044454Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2144454Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2244454Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2344454Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2444454Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2544454Ssos */ 2644454Ssos 27119418Sobrien#include <sys/cdefs.h> 28119418Sobrien__FBSDID("$FreeBSD$"); 29119418Sobrien 3044454Ssos#include <sys/param.h> 3144454Ssos#include <sys/systm.h> 3274302Ssos#include <sys/ata.h> 3344454Ssos#include <sys/kernel.h> 34144330Ssos#include <sys/module.h> 3544454Ssos#include <sys/malloc.h> 3660041Sphk#include <sys/bio.h> 3754594Ssos#include <sys/bus.h> 3851520Ssos#include <sys/conf.h> 39156320Ssos#include <sys/endian.h> 4044454Ssos#include <sys/cdio.h> 41124403Ssos#include <sys/sema.h> 42119404Ssos#include <sys/taskqueue.h> 43124534Ssos#include <vm/uma.h> 4493882Ssos#include <machine/bus.h> 45112946Sphk#include <geom/geom_disk.h> 4644454Ssos#include <dev/ata/ata-all.h> 4744454Ssos#include <dev/ata/atapi-fd.h> 48144330Ssos#include <ata_if.h> 4944454Ssos 50144330Ssos 5151520Ssos/* prototypes */ 52144330Ssosstatic disk_open_t afd_open; 53144330Ssosstatic disk_close_t afd_close; 54144330Ssosstatic disk_strategy_t afd_strategy; 55146266Ssosstatic disk_ioctl_t afd_ioctl; 56144330Ssosstatic int afd_sense(device_t); 57144330Ssosstatic void afd_describe(device_t); 58119404Ssosstatic void afd_done(struct ata_request *); 59144330Ssosstatic int afd_prevent_allow(device_t, int); 60144330Ssosstatic int afd_test_ready(device_t); 6144454Ssos 6251520Ssos/* internal vars */ 63151897Srwatsonstatic MALLOC_DEFINE(M_AFD, "afd_driver", "ATAPI floppy driver buffers"); 6451520Ssos 65144330Ssosstatic int 66144330Ssosafd_probe(device_t dev) 67144330Ssos{ 68145102Ssos struct ata_device *atadev = device_get_softc(dev); 69145102Ssos if ((atadev->param.config & ATA_PROTO_ATAPI) && 70145102Ssos (atadev->param.config & ATA_ATAPI_TYPE_MASK) == ATA_ATAPI_TYPE_DIRECT) 71145102Ssos return 0; 72145102Ssos else 73145102Ssos return ENXIO; 74144330Ssos} 75144330Ssos 76144330Ssosstatic int 77144330Ssosafd_attach(device_t dev) 78144330Ssos{ 79144330Ssos struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 80144330Ssos struct ata_device *atadev = device_get_softc(dev); 8144454Ssos struct afd_softc *fdp; 8244454Ssos 83144330Ssos if (!(fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO))) { 84144330Ssos device_printf(dev, "out of memory\n"); 85144330Ssos return ENOMEM; 8644454Ssos } 87144330Ssos device_set_ivars(dev, fdp); 88200171Smav ata_setmode(dev); 8974564Ssos 90144330Ssos if (afd_sense(dev)) { 91144330Ssos device_set_ivars(dev, NULL); 9252067Ssos free(fdp, M_AFD); 93144330Ssos return ENXIO; 9444454Ssos } 95119404Ssos atadev->flags |= ATA_D_MEDIA_CHANGED; 96119404Ssos 97144330Ssos /* announce we are here */ 98144330Ssos afd_describe(dev); 99144330Ssos 100144330Ssos /* create the disk device */ 101125975Sphk fdp->disk = disk_alloc(); 102125975Sphk fdp->disk->d_open = afd_open; 103125975Sphk fdp->disk->d_close = afd_close; 104144330Ssos fdp->disk->d_strategy = afd_strategy; 105146266Ssos fdp->disk->d_ioctl = afd_ioctl; 106125975Sphk fdp->disk->d_name = "afd"; 107144330Ssos fdp->disk->d_drv1 = dev; 108178856Sgrehan fdp->disk->d_maxsize = ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS; 109144330Ssos fdp->disk->d_unit = device_get_unit(dev); 110125975Sphk disk_create(fdp->disk, DISK_VERSION); 111144330Ssos return 0; 11244454Ssos} 11344454Ssos 114144330Ssosstatic int 115144330Ssosafd_detach(device_t dev) 11657325Ssos{ 117144330Ssos struct afd_softc *fdp = device_get_ivars(dev); 118156320Ssos 119156320Ssos /* check that we have a valid device to detach */ 120156320Ssos if (!device_get_ivars(dev)) 121156320Ssos return ENXIO; 12257325Ssos 123144330Ssos /* detroy disk from the system so we dont get any further requests */ 124125975Sphk disk_destroy(fdp->disk); 125144330Ssos 126144330Ssos /* fail requests on the queue and any thats "in flight" for this device */ 127145713Ssos ata_fail_requests(dev); 128144330Ssos 129144330Ssos /* dont leave anything behind */ 130144330Ssos device_set_ivars(dev, NULL); 13157325Ssos free(fdp, M_AFD); 132144330Ssos return 0; 133144330Ssos} 13457325Ssos 135188126Simpstatic int 136144330Ssosafd_shutdown(device_t dev) 13744454Ssos{ 138144330Ssos struct ata_device *atadev = device_get_softc(dev); 13944454Ssos 140144330Ssos if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) 141145713Ssos ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0); 142188126Simp return 0; 14344454Ssos} 14444454Ssos 145144330Ssosstatic int 146144330Ssosafd_reinit(device_t dev) 14744454Ssos{ 148144330Ssos struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 149144330Ssos struct ata_device *atadev = device_get_softc(dev); 150188897Smav 151188897Smav /* if detach pending, return error */ 152188897Smav if (!(ch->devices & (ATA_ATAPI_MASTER << atadev->unit))) 153144330Ssos return 1; 154188897Smav 155200171Smav ata_setmode(dev); 156144330Ssos return 0; 15744454Ssos} 15844454Ssos 15944475Ssosstatic int 160119404Ssosafd_open(struct disk *dp) 16144454Ssos{ 162144330Ssos device_t dev = dp->d_drv1; 163144330Ssos struct ata_device *atadev = device_get_softc(dev); 164144330Ssos struct afd_softc *fdp = device_get_ivars(dev); 16544454Ssos 166144330Ssos if (!fdp) 167119404Ssos return ENXIO; 168144330Ssos if (!device_is_attached(dev)) 169144330Ssos return EBUSY; 170107562Ssos 171144330Ssos afd_test_ready(dev); 172144330Ssos afd_prevent_allow(dev, 1); 17356819Ssos 174144330Ssos if (afd_sense(dev)) 175144330Ssos device_printf(dev, "sense media type failed\n"); 176144330Ssos atadev->flags &= ~ATA_D_MEDIA_CHANGED; 17756819Ssos 178156320Ssos if (!fdp->mediasize) 179156396Ssos return ENXIO; 180156320Ssos 181156320Ssos fdp->disk->d_sectorsize = fdp->sectorsize; 182156320Ssos fdp->disk->d_mediasize = fdp->mediasize; 183156320Ssos fdp->disk->d_fwsectors = fdp->sectors; 184156320Ssos fdp->disk->d_fwheads = fdp->heads; 18551520Ssos return 0; 18644454Ssos} 18744454Ssos 18844475Ssosstatic int 189119404Ssosafd_close(struct disk *dp) 19044454Ssos{ 191144330Ssos device_t dev = dp->d_drv1; 19244454Ssos 193144330Ssos afd_prevent_allow(dev, 0); 19444454Ssos return 0; 19544454Ssos} 19644454Ssos 19744454Ssosstatic void 198144330Ssosafd_strategy(struct bio *bp) 19944454Ssos{ 200144330Ssos device_t dev = bp->bio_disk->d_drv1; 201144330Ssos struct ata_device *atadev = device_get_softc(dev); 202144330Ssos struct afd_softc *fdp = device_get_ivars(dev); 203144330Ssos struct ata_request *request; 204144330Ssos u_int16_t count; 205144330Ssos int8_t ccb[16]; 20644454Ssos 20798429Ssos /* if it's a null transfer, return immediatly. */ 20898429Ssos if (bp->bio_bcount == 0) { 20998429Ssos bp->bio_resid = 0; 21098429Ssos biodone(bp); 21198429Ssos return; 21298429Ssos } 21398429Ssos 21448213Ssos /* should reject all queued entries if media have changed. */ 215144330Ssos if (atadev->flags & ATA_D_MEDIA_CHANGED) { 21676322Sphk biofinish(bp, NULL, EIO); 21751520Ssos return; 21844454Ssos } 21944454Ssos 220156320Ssos count = bp->bio_bcount / fdp->sectorsize; 22198429Ssos bp->bio_resid = bp->bio_bcount; 22244454Ssos 22347272Ssos bzero(ccb, sizeof(ccb)); 22447272Ssos 22559249Sphk if (bp->bio_cmd == BIO_READ) 22644454Ssos ccb[0] = ATAPI_READ_BIG; 22744454Ssos else 22844454Ssos ccb[0] = ATAPI_WRITE_BIG; 22944454Ssos 230144330Ssos ccb[2] = bp->bio_pblkno >> 24; 231144330Ssos ccb[3] = bp->bio_pblkno >> 16; 232144330Ssos ccb[4] = bp->bio_pblkno >> 8; 233144330Ssos ccb[5] = bp->bio_pblkno; 23444454Ssos ccb[7] = count>>8; 23544454Ssos ccb[8] = count; 23644454Ssos 237178278Ssos if (!(request = ata_alloc_request())) { 238124419Ssos biofinish(bp, NULL, ENOMEM); 239119404Ssos return; 240119404Ssos } 241178278Ssos request->dev = dev; 242144330Ssos request->bio = bp; 243198407Smav bcopy(ccb, request->u.atapi.ccb, 16); 244119404Ssos request->data = bp->bio_data; 245156320Ssos request->bytecount = count * fdp->sectorsize; 246119404Ssos request->transfersize = min(request->bytecount, 65534); 247119404Ssos request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30; 248119404Ssos request->retries = 2; 249119404Ssos request->callback = afd_done; 250119404Ssos switch (bp->bio_cmd) { 251119404Ssos case BIO_READ: 252144330Ssos request->flags = (ATA_R_ATAPI | ATA_R_READ); 253119404Ssos break; 254119404Ssos case BIO_WRITE: 255144330Ssos request->flags = (ATA_R_ATAPI | ATA_R_WRITE); 256119404Ssos break; 257119404Ssos default: 258144330Ssos device_printf(dev, "unknown BIO operation\n"); 259119404Ssos ata_free_request(request); 260119404Ssos biofinish(bp, NULL, EIO); 261119404Ssos return; 262119404Ssos } 263144330Ssos if (atadev->mode >= ATA_DMA) 264144330Ssos request->flags |= ATA_R_DMA; 265144330Ssos request->flags |= ATA_R_ORDERED; 266119404Ssos ata_queue_request(request); 26747334Ssos} 26844454Ssos 269119404Ssosstatic void 270119404Ssosafd_done(struct ata_request *request) 27144454Ssos{ 272144330Ssos struct bio *bp = request->bio; 27344454Ssos 274119404Ssos /* finish up transfer */ 275119404Ssos if ((bp->bio_error = request->result)) 27659249Sphk bp->bio_flags |= BIO_ERROR; 277119404Ssos bp->bio_resid = bp->bio_bcount - request->donecount; 278111979Sphk biodone(bp); 279119404Ssos ata_free_request(request); 28044454Ssos} 28144454Ssos 282146266Ssosstatic int 283146266Ssosafd_ioctl(struct disk *disk, u_long cmd, void *data, int flag,struct thread *td) 284146266Ssos{ 285146266Ssos return ata_device_ioctl(disk->d_drv1, cmd, data); 286146266Ssos} 287146266Ssos 28866070Ssosstatic int 289144330Ssosafd_sense(device_t dev) 29044454Ssos{ 291144330Ssos struct ata_device *atadev = device_get_softc(dev); 292144330Ssos struct afd_softc *fdp = device_get_ivars(dev); 293156320Ssos struct afd_capacity capacity; 294156320Ssos struct afd_capacity_big capacity_big; 295156320Ssos struct afd_capabilities capabilities; 296156320Ssos int8_t ccb1[16] = { ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 297156320Ssos 0, 0, 0, 0, 0, 0, 0, 0 }; 298156320Ssos int8_t ccb2[16] = { ATAPI_SERVICE_ACTION_IN, 0x10, 0, 0, 0, 0, 0, 0, 0, 0, 299156320Ssos 0, 0, 0, sizeof(struct afd_capacity_big) & 0xff, 0, 0 }; 300156320Ssos int8_t ccb3[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE, 301156320Ssos 0, 0, 0, 0, sizeof(struct afd_capabilities) >> 8, 302156320Ssos sizeof(struct afd_capabilities) & 0xff, 303156320Ssos 0, 0, 0, 0, 0, 0, 0 }; 304156396Ssos int timeout = 20; 305156425Ssos int error, count; 306144330Ssos 307156425Ssos fdp->mediasize = 0; 308156425Ssos 309156396Ssos /* wait for device to get ready */ 310156425Ssos while ((error = afd_test_ready(dev)) && timeout--) { 311156396Ssos DELAY(100000); 312156425Ssos } 313156838Ssos if (error == EBUSY) 314156425Ssos return 1; 315156320Ssos 316144330Ssos /* The IOMEGA Clik! doesn't support reading the cap page, fake it */ 317144330Ssos if (!strncmp(atadev->param.model, "IOMEGA Clik!", 12)) { 318156320Ssos fdp->heads = 1; 319156320Ssos fdp->sectors = 2; 320156320Ssos fdp->mediasize = 39441 * 1024; 321156320Ssos fdp->sectorsize = 512; 322144330Ssos afd_test_ready(dev); 323144330Ssos return 0; 324144330Ssos } 325144330Ssos 326156320Ssos /* get drive capacity */ 327156320Ssos if (!ata_atapicmd(dev, ccb1, (caddr_t)&capacity, 328156320Ssos sizeof(struct afd_capacity), ATA_R_READ, 30)) { 329156320Ssos fdp->heads = 16; 330156320Ssos fdp->sectors = 63; 331156320Ssos fdp->sectorsize = be32toh(capacity.blocksize); 332156320Ssos fdp->mediasize = (u_int64_t)be32toh(capacity.capacity)*fdp->sectorsize; 333156320Ssos afd_test_ready(dev); 334156320Ssos return 0; 335156320Ssos } 336156320Ssos 337156320Ssos /* get drive capacity big */ 338156320Ssos if (!ata_atapicmd(dev, ccb2, (caddr_t)&capacity_big, 339156320Ssos sizeof(struct afd_capacity_big), 340156320Ssos ATA_R_READ | ATA_R_QUIET, 30)) { 341156320Ssos fdp->heads = 16; 342156320Ssos fdp->sectors = 63; 343156320Ssos fdp->sectorsize = be32toh(capacity_big.blocksize); 344156320Ssos fdp->mediasize = be64toh(capacity_big.capacity)*fdp->sectorsize; 345156320Ssos afd_test_ready(dev); 346156320Ssos return 0; 347156320Ssos } 348156320Ssos 349144330Ssos /* get drive capabilities, some bugridden drives needs this repeated */ 350144330Ssos for (count = 0 ; count < 5 ; count++) { 351156320Ssos if (!ata_atapicmd(dev, ccb3, (caddr_t)&capabilities, 352156320Ssos sizeof(struct afd_capabilities), ATA_R_READ, 30) && 353156320Ssos capabilities.page_code == ATAPI_REWRITEABLE_CAP_PAGE) { 354156320Ssos fdp->heads = capabilities.heads; 355156320Ssos fdp->sectors = capabilities.sectors; 356156320Ssos fdp->sectorsize = be16toh(capabilities.sector_size); 357156320Ssos fdp->mediasize = be16toh(capabilities.cylinders) * 358156320Ssos fdp->heads * fdp->sectors * fdp->sectorsize; 359156320Ssos if (!capabilities.medium_type) 360156320Ssos fdp->mediasize = 0; 36151520Ssos return 0; 362144330Ssos } 36344454Ssos } 364144330Ssos return 1; 36544454Ssos} 36644454Ssos 36766070Ssosstatic int 368144330Ssosafd_prevent_allow(device_t dev, int lock) 36944454Ssos{ 370144330Ssos struct ata_device *atadev = device_get_softc(dev); 37151520Ssos int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 37251520Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 37351520Ssos 374144330Ssos if (!strncmp(atadev->param.model, "IOMEGA Clik!", 12)) 37574251Ssos return 0; 376145713Ssos return ata_atapicmd(dev, ccb, NULL, 0, 0, 30); 37751520Ssos} 378119404Ssos 379119404Ssosstatic int 380144330Ssosafd_test_ready(device_t dev) 381119404Ssos{ 382119404Ssos int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 383119404Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 384119404Ssos 385145713Ssos return ata_atapicmd(dev, ccb, NULL, 0, 0, 30); 386119404Ssos} 387144330Ssos 388144330Ssosstatic void 389144330Ssosafd_describe(device_t dev) 390144330Ssos{ 391144330Ssos struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 392144330Ssos struct ata_device *atadev = device_get_softc(dev); 393144330Ssos struct afd_softc *fdp = device_get_ivars(dev); 394157283Smarcel char sizestring[16]; 395144330Ssos 396156320Ssos if (fdp->mediasize > 1048576 * 5) 397156320Ssos sprintf(sizestring, "%juMB", fdp->mediasize / 1048576); 398156320Ssos else if (fdp->mediasize) 399156320Ssos sprintf(sizestring, "%juKB", fdp->mediasize / 1024); 400156320Ssos else 401156320Ssos strcpy(sizestring, "(no media)"); 402156320Ssos 403200171Smav device_printf(dev, "%s <%.40s %.8s> at ata%d-%s %s %s\n", 404156320Ssos sizestring, atadev->param.model, atadev->param.revision, 405178067Ssos device_get_unit(ch->dev), ata_unit2str(atadev), 406200171Smav ata_mode2str(atadev->mode), 407200171Smav ata_satarev2str(ATA_GETREV(device_get_parent(dev), atadev->unit))); 408144330Ssos if (bootverbose) { 409156320Ssos device_printf(dev, "%ju sectors [%juC/%dH/%dS]\n", 410156320Ssos fdp->mediasize / fdp->sectorsize, 411156320Ssos fdp->mediasize /(fdp->sectorsize*fdp->sectors*fdp->heads), 412156320Ssos fdp->heads, fdp->sectors); 413144330Ssos } 414144330Ssos} 415144330Ssos 416144330Ssosstatic device_method_t afd_methods[] = { 417144330Ssos /* device interface */ 418144330Ssos DEVMETHOD(device_probe, afd_probe), 419144330Ssos DEVMETHOD(device_attach, afd_attach), 420144330Ssos DEVMETHOD(device_detach, afd_detach), 421144330Ssos DEVMETHOD(device_shutdown, afd_shutdown), 422144330Ssos 423144330Ssos /* ATA methods */ 424144330Ssos DEVMETHOD(ata_reinit, afd_reinit), 425144330Ssos 426233717Smarius DEVMETHOD_END 427144330Ssos}; 428144330Ssos 429144330Ssosstatic driver_t afd_driver = { 430144330Ssos "afd", 431144330Ssos afd_methods, 432144397Ssos 0, 433144330Ssos}; 434144330Ssos 435144330Ssosstatic devclass_t afd_devclass; 436144330Ssos 437145102SsosDRIVER_MODULE(afd, ata, afd_driver, afd_devclass, NULL, NULL); 438144330SsosMODULE_VERSION(afd, 1); 439144330SsosMODULE_DEPEND(afd, ata, 1, 1, 1); 440144330Ssos 441