144380Ssos/*- 2178067Ssos * Copyright (c) 1998 - 2008 S�ren Schmidt <sos@FreeBSD.org> 344380Ssos * All rights reserved. 444380Ssos * 544380Ssos * Redistribution and use in source and binary forms, with or without 644380Ssos * modification, are permitted provided that the following conditions 744380Ssos * are met: 844380Ssos * 1. Redistributions of source code must retain the above copyright 944380Ssos * notice, this list of conditions and the following disclaimer, 1044380Ssos * without modification, immediately at the beginning of the file. 1144380Ssos * 2. Redistributions in binary form must reproduce the above copyright 1244380Ssos * notice, this list of conditions and the following disclaimer in the 1344380Ssos * documentation and/or other materials provided with the distribution. 1444380Ssos * 1544380Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1644380Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1744380Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1844380Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1944380Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2044380Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2144380Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2244380Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2344380Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2444380Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2544380Ssos */ 2644380Ssos 27119418Sobrien#include <sys/cdefs.h> 28119418Sobrien__FBSDID("$FreeBSD$"); 29119418Sobrien 3090681Sbde#include "opt_ata.h" 3144380Ssos#include <sys/param.h> 3244380Ssos#include <sys/systm.h> 3374302Ssos#include <sys/ata.h> 3444380Ssos#include <sys/kernel.h> 35144330Ssos#include <sys/module.h> 36144330Ssos#include <sys/malloc.h> 3744380Ssos#include <sys/conf.h> 3860041Sphk#include <sys/bio.h> 3954594Ssos#include <sys/bus.h> 4044380Ssos#include <sys/mtio.h> 4144380Ssos#include <sys/devicestat.h> 42124403Ssos#include <sys/sema.h> 43119404Ssos#include <sys/taskqueue.h> 44124534Ssos#include <vm/uma.h> 4593882Ssos#include <machine/bus.h> 4644380Ssos#include <dev/ata/ata-all.h> 4744380Ssos#include <dev/ata/atapi-tape.h> 48144330Ssos#include <ata_if.h> 4944380Ssos 50144330Ssos/* device structure */ 51144330Ssosstatic d_open_t ast_open; 52144330Ssosstatic d_close_t ast_close; 53144330Ssosstatic d_ioctl_t ast_ioctl; 54144330Ssosstatic d_strategy_t ast_strategy; 5544380Ssosstatic struct cdevsw ast_cdevsw = { 56144330Ssos .d_version = D_VERSION, 57144330Ssos .d_open = ast_open, 58144330Ssos .d_close = ast_close, 59144330Ssos .d_read = physread, 60144330Ssos .d_write = physwrite, 61144330Ssos .d_ioctl = ast_ioctl, 62144330Ssos .d_strategy = ast_strategy, 63144330Ssos .d_name = "ast", 64144330Ssos .d_flags = D_TAPE | D_TRACKCLOSE, 6544566Ssos}; 6644380Ssos 6751520Ssos/* prototypes */ 68144330Ssosstatic int ast_sense(device_t); 69144330Ssosstatic void ast_describe(device_t); 70119404Ssosstatic void ast_done(struct ata_request *); 71144330Ssosstatic int ast_mode_sense(device_t, int, void *, int); 72144330Ssosstatic int ast_mode_select(device_t, void *, int); 73144330Ssosstatic int ast_write_filemark(device_t, u_int8_t); 74144330Ssosstatic int ast_read_position(device_t, int, struct ast_readposition *); 75144330Ssosstatic int ast_space(device_t, u_int8_t, int32_t); 76144330Ssosstatic int ast_locate(device_t, int, u_int32_t); 77144330Ssosstatic int ast_prevent_allow(device_t, int); 78144330Ssosstatic int ast_load_unload(device_t, u_int8_t); 79144330Ssosstatic int ast_rewind(device_t); 80144330Ssosstatic int ast_erase(device_t); 81144330Ssosstatic int ast_test_ready(device_t); 82144330Ssosstatic int ast_wait_dsc(device_t, int); 8344380Ssos 8451520Ssos/* internal vars */ 8551520Ssosstatic u_int64_t ast_total = 0; 86151897Srwatsonstatic MALLOC_DEFINE(M_AST, "ast_driver", "ATAPI tape driver buffers"); 8751520Ssos 88144330Ssosstatic int 89144330Ssosast_probe(device_t dev) 90144330Ssos{ 91145102Ssos struct ata_device *atadev = device_get_softc(dev); 92145102Ssos 93145102Ssos if ((atadev->param.config & ATA_PROTO_ATAPI) && 94145102Ssos (atadev->param.config & ATA_ATAPI_TYPE_MASK) == ATA_ATAPI_TYPE_TAPE) 95145102Ssos return 0; 96145102Ssos else 97145102Ssos return ENXIO; 98144330Ssos} 99144330Ssos 100144330Ssosstatic int 101144330Ssosast_attach(device_t dev) 102144330Ssos{ 103144330Ssos struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 104144330Ssos struct ata_device *atadev = device_get_softc(dev); 10544380Ssos struct ast_softc *stp; 10651520Ssos struct ast_readposition position; 107144330Ssos struct cdev *device; 10844380Ssos 109144330Ssos if (!(stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO))) { 110144330Ssos device_printf(dev, "out of memory\n"); 111144330Ssos return ENOMEM; 11244380Ssos } 113144330Ssos device_set_ivars(dev, stp); 114200171Smav ata_setmode(dev); 11574564Ssos 116144330Ssos if (ast_sense(dev)) { 117144330Ssos device_set_ivars(dev, NULL); 11852067Ssos free(stp, M_AST); 119144330Ssos return ENXIO; 12044380Ssos } 121144330Ssos if (!strcmp(atadev->param.model, "OnStream DI-30")) { 12251520Ssos struct ast_transferpage transfer; 12351520Ssos struct ast_identifypage identify; 12444380Ssos 12551520Ssos stp->flags |= F_ONSTREAM; 12651520Ssos bzero(&transfer, sizeof(struct ast_transferpage)); 127144330Ssos ast_mode_sense(dev, ATAPI_TAPE_TRANSFER_PAGE, 12851520Ssos &transfer, sizeof(transfer)); 12951520Ssos bzero(&identify, sizeof(struct ast_identifypage)); 130144330Ssos ast_mode_sense(dev, ATAPI_TAPE_IDENTIFY_PAGE, 13151520Ssos &identify, sizeof(identify)); 13251520Ssos strncpy(identify.ident, "FBSD", 4); 133144330Ssos ast_mode_select(dev, &identify, sizeof(identify)); 134144330Ssos ast_read_position(dev, 0, &position); 13551520Ssos } 13674564Ssos 137144330Ssos stp->stats = devstat_new_entry("ast", device_get_unit(dev), DEV_BSIZE, 13851520Ssos DEVSTAT_NO_ORDERED_TAGS, 13951520Ssos DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE, 14054306Ssos DEVSTAT_PRIORITY_TAPE); 141191516Sed device = make_dev(&ast_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0640, 142191516Sed "ast%d", device_get_unit(dev)); 143144330Ssos device->si_drv1 = dev; 144178856Sgrehan device->si_iosize_max = ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS; 145144330Ssos stp->dev1 = device; 146191516Sed device = make_dev(&ast_cdevsw, 1, UID_ROOT, GID_OPERATOR, 0640, 147191516Sed "nast%d", device_get_unit(dev)); 148144330Ssos device->si_drv1 = dev; 149178067Ssos device->si_iosize_max = ch->dma.max_iosize; 150144330Ssos stp->dev2 = device; 151119404Ssos 152144330Ssos /* announce we are here and ready */ 153144330Ssos ast_describe(dev); 154144330Ssos return 0; 15544380Ssos} 15644380Ssos 157144330Ssosstatic int 158144330Ssosast_detach(device_t dev) 15957325Ssos{ 160144330Ssos struct ast_softc *stp = device_get_ivars(dev); 16157325Ssos 162144330Ssos /* detroy devices from the system so we dont get any further requests */ 16357325Ssos destroy_dev(stp->dev1); 16457325Ssos destroy_dev(stp->dev2); 165144330Ssos 166144330Ssos /* fail requests on the queue and any thats "in flight" for this device */ 167145713Ssos ata_fail_requests(dev); 168144330Ssos 169144330Ssos /* dont leave anything behind */ 170112004Sphk devstat_remove_entry(stp->stats); 171144330Ssos device_set_ivars(dev, NULL); 17257325Ssos free(stp, M_AST); 173144330Ssos return 0; 17457325Ssos} 17557325Ssos 176188126Simpstatic int 177144330Ssosast_shutdown(device_t dev) 17844380Ssos{ 179144330Ssos struct ata_device *atadev = device_get_softc(dev); 18044380Ssos 181144330Ssos if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE) 182145713Ssos ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0); 183188126Simp return 0; 18444380Ssos} 18544380Ssos 186144330Ssosstatic int 187144330Ssosast_reinit(device_t dev) 18844380Ssos{ 189144330Ssos struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 190144330Ssos struct ata_device *atadev = device_get_softc(dev); 191144330Ssos 192188897Smav /* if detach pending, return error */ 193188897Smav if (!(ch->devices & (ATA_ATAPI_MASTER << atadev->unit))) 194144330Ssos return 1; 195188897Smav 196200171Smav ata_setmode(dev); 197144330Ssos return 0; 19844380Ssos} 19944380Ssos 20044475Ssosstatic int 201144330Ssosast_open(struct cdev *cdev, int flags, int fmt, struct thread *td) 20244380Ssos{ 203144330Ssos device_t dev = cdev->si_drv1; 204144330Ssos struct ata_device *atadev = device_get_softc(dev); 205144330Ssos struct ast_softc *stp = device_get_ivars(dev); 20644380Ssos 207144330Ssos if (!stp) 20853078Ssos return ENXIO; 209144330Ssos if (!device_is_attached(dev)) 21051520Ssos return EBUSY; 21151520Ssos 212144330Ssos ast_test_ready(dev); 21351520Ssos if (stp->cap.lock) 214144330Ssos ast_prevent_allow(dev, 1); 215144330Ssos if (ast_sense(dev)) 216144330Ssos device_printf(dev, "sense media type failed\n"); 21751520Ssos 218144330Ssos atadev->flags &= ~ATA_D_MEDIA_CHANGED; 21944380Ssos stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN); 22044380Ssos ast_total = 0; 22144454Ssos return 0; 22244380Ssos} 22344380Ssos 22444475Ssosstatic int 225144330Ssosast_close(struct cdev *cdev, int flags, int fmt, struct thread *td) 22644380Ssos{ 227144330Ssos device_t dev = cdev->si_drv1; 228144330Ssos struct ast_softc *stp = device_get_ivars(dev); 22944380Ssos 23051520Ssos /* flush buffers, some drives fail here, they should report ctl = 0 */ 23144380Ssos if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN)) 232144330Ssos ast_write_filemark(dev, 0); 23344380Ssos 23448213Ssos /* write filemark if data written to tape */ 23551520Ssos if (!(stp->flags & F_ONSTREAM) && 23651520Ssos (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN) 237144330Ssos ast_write_filemark(dev, ATAPI_WF_WRITE); 23844380Ssos 239191516Sed /* if unit is zero rewind on close */ 240191516Sed if (dev2unit(cdev) == 0) 241144330Ssos ast_rewind(dev); 24244380Ssos 243144330Ssos if (stp->cap.lock && count_dev(cdev) == 1) 244144330Ssos ast_prevent_allow(dev, 0); 24551520Ssos 246114728Ssos stp->flags &= ~F_CTL_WARN; 24744380Ssos#ifdef AST_DEBUG 248144330Ssos device_printf(dev, "%ju total bytes transferred\n", (uintmax_t)ast_total); 24944380Ssos#endif 25044454Ssos return 0; 25144380Ssos} 25244380Ssos 25344475Ssosstatic int 254146266Ssosast_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flag, struct thread *td) 25544380Ssos{ 256144330Ssos device_t dev = cdev->si_drv1; 257144330Ssos struct ast_softc *stp = device_get_ivars(dev); 25866070Ssos int error = 0; 25944380Ssos 26044380Ssos switch (cmd) { 26144380Ssos case MTIOCGET: 26244380Ssos { 263146266Ssos struct mtget *g = (struct mtget *) data; 26444380Ssos 26551520Ssos bzero(g, sizeof(struct mtget)); 26651520Ssos g->mt_type = 7; 26751520Ssos g->mt_density = 1; 26851520Ssos g->mt_blksiz = stp->blksize; 26951520Ssos g->mt_comp = stp->cap.compress; 27051520Ssos g->mt_density0 = 0; g->mt_density1 = 0; 27151520Ssos g->mt_density2 = 0; g->mt_density3 = 0; 27251520Ssos g->mt_blksiz0 = 0; g->mt_blksiz1 = 0; 27351520Ssos g->mt_blksiz2 = 0; g->mt_blksiz3 = 0; 27451520Ssos g->mt_comp0 = 0; g->mt_comp1 = 0; 27551520Ssos g->mt_comp2 = 0; g->mt_comp3 = 0; 27644380Ssos } 277144330Ssos break; 278119450Ssos 27944380Ssos case MTIOCTOP: 280144330Ssos { 28166070Ssos int i; 282146266Ssos struct mtop *mt = (struct mtop *)data; 28344380Ssos 28451520Ssos switch ((int16_t) (mt->mt_op)) { 28548213Ssos 28651520Ssos case MTWEOF: 28744380Ssos for (i=0; i < mt->mt_count && !error; i++) 288144330Ssos error = ast_write_filemark(dev, ATAPI_WF_WRITE); 28951520Ssos break; 29048213Ssos 29151520Ssos case MTFSF: 29244380Ssos if (mt->mt_count) 293144330Ssos error = ast_space(dev, ATAPI_SP_FM, mt->mt_count); 29451520Ssos break; 29548213Ssos 29651520Ssos case MTBSF: 29744380Ssos if (mt->mt_count) 298144330Ssos error = ast_space(dev, ATAPI_SP_FM, -(mt->mt_count)); 29951520Ssos break; 30048213Ssos 30151520Ssos case MTREW: 302144330Ssos error = ast_rewind(dev); 30344380Ssos break; 30448213Ssos 30551520Ssos case MTOFFL: 306144330Ssos error = ast_load_unload(dev, ATAPI_SS_EJECT); 30748213Ssos break; 30848213Ssos 30951520Ssos case MTNOP: 310144330Ssos error = ast_write_filemark(dev, 0); 31151520Ssos break; 31248213Ssos 31351520Ssos case MTERASE: 314144330Ssos error = ast_erase(dev); 31544380Ssos break; 31648213Ssos 31751520Ssos case MTEOD: 318144330Ssos error = ast_space(dev, ATAPI_SP_EOD, 0); 31951520Ssos break; 32048213Ssos 32151520Ssos case MTRETENS: 322144330Ssos error = ast_load_unload(dev, ATAPI_SS_RETENSION|ATAPI_SS_LOAD); 32344380Ssos break; 32448213Ssos 325144330Ssos case MTFSR: 32651520Ssos case MTBSR: 32751520Ssos case MTCACHE: 32851520Ssos case MTNOCACHE: 32951520Ssos case MTSETBSIZ: 33051520Ssos case MTSETDNSTY: 33151520Ssos case MTCOMP: 33251520Ssos default: 33351520Ssos error = EINVAL; 33451520Ssos } 33551520Ssos } 336119450Ssos break; 337119450Ssos 33851520Ssos case MTIOCRDSPOS: 33951520Ssos { 34051520Ssos struct ast_readposition position; 34151520Ssos 342144330Ssos if ((error = ast_read_position(dev, 0, &position))) 34351520Ssos break; 344146266Ssos *(u_int32_t *)data = position.tape; 34551520Ssos } 346119450Ssos break; 347119450Ssos 34851520Ssos case MTIOCRDHPOS: 34951520Ssos { 35051520Ssos struct ast_readposition position; 35151520Ssos 352144330Ssos if ((error = ast_read_position(dev, 1, &position))) 35351520Ssos break; 354146266Ssos *(u_int32_t *)data = position.tape; 35551520Ssos } 356119450Ssos break; 357119450Ssos 35851520Ssos case MTIOCSLOCATE: 359146266Ssos error = ast_locate(dev, 0, *(u_int32_t *)data); 36051520Ssos break; 361119450Ssos 36251520Ssos case MTIOCHLOCATE: 363146266Ssos error = ast_locate(dev, 1, *(u_int32_t *)data); 36451520Ssos break; 365119450Ssos 36644380Ssos default: 367146266Ssos error = ata_device_ioctl(dev, cmd, data); 36844380Ssos } 36944454Ssos return error; 37044380Ssos} 37144380Ssos 37244454Ssosstatic void 373119404Ssosast_strategy(struct bio *bp) 37444454Ssos{ 375144330Ssos device_t dev = bp->bio_dev->si_drv1; 376144330Ssos struct ast_softc *stp = device_get_ivars(dev); 377144330Ssos struct ata_request *request; 378144330Ssos u_int32_t blkcount; 379144330Ssos int8_t ccb[16]; 38044454Ssos 38148213Ssos /* if it's a null transfer, return immediatly. */ 38259249Sphk if (bp->bio_bcount == 0) { 38359249Sphk bp->bio_resid = 0; 38451520Ssos biodone(bp); 38551520Ssos return; 38644454Ssos } 38759249Sphk if (!(bp->bio_cmd == BIO_READ) && stp->flags & F_WRITEPROTECT) { 38876322Sphk biofinish(bp, NULL, EPERM); 38951520Ssos return; 39051520Ssos } 39151520Ssos 39248213Ssos /* check for != blocksize requests */ 39359249Sphk if (bp->bio_bcount % stp->blksize) { 394144330Ssos device_printf(dev, "transfers must be multiple of %d\n", stp->blksize); 39576322Sphk biofinish(bp, NULL, EIO); 39651520Ssos return; 39744454Ssos } 39848213Ssos 39948213Ssos /* warn about transfers bigger than the device suggests */ 400144330Ssos if (bp->bio_bcount > stp->blksize * stp->cap.ctl) { 40144454Ssos if ((stp->flags & F_CTL_WARN) == 0) { 402144330Ssos device_printf(dev, "WARNING: CTL exceeded %ld>%d\n", 403144330Ssos bp->bio_bcount, stp->blksize * stp->cap.ctl); 40444454Ssos stp->flags |= F_CTL_WARN; 40544454Ssos } 40644454Ssos } 40744454Ssos 40844454Ssos bzero(ccb, sizeof(ccb)); 40951520Ssos 41059249Sphk if (bp->bio_cmd == BIO_READ) 41151520Ssos ccb[0] = ATAPI_READ; 41258260Ssos else 41351520Ssos ccb[0] = ATAPI_WRITE; 41451520Ssos 41559249Sphk blkcount = bp->bio_bcount / stp->blksize; 41651520Ssos 41744454Ssos ccb[1] = 1; 418144330Ssos ccb[2] = blkcount >> 16; 419144330Ssos ccb[3] = blkcount >> 8; 42044454Ssos ccb[4] = blkcount; 42144454Ssos 422178278Ssos if (!(request = ata_alloc_request())) { 423124419Ssos biofinish(bp, NULL, ENOMEM); 424119404Ssos return; 425119404Ssos } 426178278Ssos request->dev = dev; 427119404Ssos request->driver = bp; 428198407Smav bcopy(ccb, request->u.atapi.ccb, 16); 429119404Ssos request->data = bp->bio_data; 430119404Ssos request->bytecount = blkcount * stp->blksize; 431119404Ssos request->transfersize = min(request->bytecount, 65534); 432119404Ssos request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 180 : 120; 433119404Ssos request->retries = 2; 434119404Ssos request->callback = ast_done; 435119404Ssos switch (bp->bio_cmd) { 436119404Ssos case BIO_READ: 437125159Ssos request->flags |= (ATA_R_ATAPI | ATA_R_READ); 438119404Ssos break; 439119404Ssos case BIO_WRITE: 440125159Ssos request->flags |= (ATA_R_ATAPI | ATA_R_WRITE); 441119404Ssos break; 442119404Ssos default: 443144330Ssos device_printf(dev, "unknown BIO operation\n"); 444119404Ssos ata_free_request(request); 445119404Ssos biofinish(bp, NULL, EIO); 446119404Ssos return; 447119404Ssos } 448112260Sphk devstat_start_transaction_bio(stp->stats, bp); 449119404Ssos ata_queue_request(request); 45044454Ssos} 45144454Ssos 452119404Ssosstatic void 453119404Ssosast_done(struct ata_request *request) 45444454Ssos{ 455144330Ssos struct ast_softc *stp = device_get_ivars(request->dev); 45659249Sphk struct bio *bp = request->driver; 45744454Ssos 458119404Ssos /* finish up transfer */ 459119404Ssos if ((bp->bio_error = request->result)) 46059249Sphk bp->bio_flags |= BIO_ERROR; 461119404Ssos if (bp->bio_cmd == BIO_WRITE) 462119404Ssos stp->flags |= F_DATA_WRITTEN; 463119404Ssos bp->bio_resid = bp->bio_bcount - request->donecount; 464119404Ssos ast_total += (bp->bio_bcount - bp->bio_resid); 465112004Sphk biofinish(bp, stp->stats, 0); 466119404Ssos ata_free_request(request); 46744454Ssos} 46844454Ssos 46966070Ssosstatic int 470144330Ssosast_sense(device_t dev) 47144380Ssos{ 472144330Ssos struct ast_softc *stp = device_get_ivars(dev); 473144330Ssos int count; 474144330Ssos 475144330Ssos /* get drive capabilities, some bugridden drives needs this repeated */ 476144330Ssos for (count = 0 ; count < 5 ; count++) { 477144330Ssos if (!ast_mode_sense(dev, ATAPI_TAPE_CAP_PAGE, 478144330Ssos &stp->cap, sizeof(stp->cap)) && 479144330Ssos stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) { 480144330Ssos if (stp->cap.blk32k) 481144330Ssos stp->blksize = 32768; 482144330Ssos if (stp->cap.blk1024) 483144330Ssos stp->blksize = 1024; 484144330Ssos if (stp->cap.blk512) 485144330Ssos stp->blksize = 512; 486144330Ssos if (!stp->blksize) 487144330Ssos continue; 488144330Ssos stp->cap.max_speed = ntohs(stp->cap.max_speed); 489144330Ssos stp->cap.max_defects = ntohs(stp->cap.max_defects); 490144330Ssos stp->cap.ctl = ntohs(stp->cap.ctl); 491144330Ssos stp->cap.speed = ntohs(stp->cap.speed); 492144330Ssos stp->cap.buffer_size = ntohs(stp->cap.buffer_size); 493144330Ssos return 0; 494144330Ssos } 495144330Ssos } 496144330Ssos return 1; 497144330Ssos} 498144330Ssos 499144330Ssosstatic int 500144330Ssosast_mode_sense(device_t dev, int page, void *pagebuf, int pagesize) 501144330Ssos{ 50251520Ssos int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize, 50351520Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 50466070Ssos int error; 50551520Ssos 506145713Ssos error = ata_atapicmd(dev, ccb, pagebuf, pagesize, ATA_R_READ, 10); 50752067Ssos return error; 50851520Ssos} 50944380Ssos 510144330Ssosstatic int 511144330Ssosast_mode_select(device_t dev, void *pagebuf, int pagesize) 51251520Ssos{ 51351520Ssos int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize, 51451520Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 51551520Ssos 516145713Ssos return ata_atapicmd(dev, ccb, pagebuf, pagesize, 0, 10); 51744380Ssos} 51844380Ssos 51966070Ssosstatic int 520144330Ssosast_write_filemark(device_t dev, u_int8_t function) 52144380Ssos{ 522144330Ssos struct ast_softc *stp = device_get_ivars(dev); 52351520Ssos int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0, 52451520Ssos 0, 0, 0, 0, 0, 0, 0, 0 }; 52566070Ssos int error; 52644380Ssos 52751520Ssos if (stp->flags & F_ONSTREAM) 528144330Ssos ccb[4] = 0x00; /* only flush buffers supported */ 52951520Ssos else { 53051520Ssos if (function) { 53151520Ssos if (stp->flags & F_FM_WRITTEN) 53251520Ssos stp->flags &= ~F_DATA_WRITTEN; 53351520Ssos else 53451520Ssos stp->flags |= F_FM_WRITTEN; 53551520Ssos } 53644380Ssos } 537145713Ssos error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10); 53851520Ssos if (error) 53952067Ssos return error; 540144330Ssos return ast_wait_dsc(dev, 10*60); 54144380Ssos} 54244380Ssos 54366070Ssosstatic int 544144330Ssosast_read_position(device_t dev, int hard, struct ast_readposition *position) 54544380Ssos{ 54651520Ssos int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0, 54751520Ssos 0, 0, 0, 0, 0, 0, 0, 0 }; 54866070Ssos int error; 54944380Ssos 550145713Ssos error = ata_atapicmd(dev, ccb, (caddr_t)position, 551119404Ssos sizeof(struct ast_readposition), ATA_R_READ, 10); 55252067Ssos position->tape = ntohl(position->tape); 55352067Ssos position->host = ntohl(position->host); 55452067Ssos return error; 55544380Ssos} 55644380Ssos 55766070Ssosstatic int 558144330Ssosast_space(device_t dev, u_int8_t function, int32_t count) 55944380Ssos{ 56051520Ssos int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count, 56151520Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 56251520Ssos 563145713Ssos return ata_atapicmd(dev, ccb, NULL, 0, 0, 60*60); 56451520Ssos} 56551520Ssos 56666070Ssosstatic int 567144330Ssosast_locate(device_t dev, int hard, u_int32_t pos) 56851520Ssos{ 56951520Ssos int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0, 57051520Ssos pos>>24, pos>>16, pos>>8, pos, 57151520Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 57266070Ssos int error; 57344380Ssos 574145713Ssos error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10); 57551520Ssos if (error) 57652067Ssos return error; 577144330Ssos return ast_wait_dsc(dev, 60*60); 57851520Ssos} 57944380Ssos 58066070Ssosstatic int 581144330Ssosast_prevent_allow(device_t dev, int lock) 58251520Ssos{ 58351520Ssos int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 58451520Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 58551520Ssos 586145713Ssos return ata_atapicmd(dev, ccb, NULL, 0, 0, 30); 58744380Ssos} 58844380Ssos 58966070Ssosstatic int 590144330Ssosast_load_unload(device_t dev, u_int8_t function) 59151520Ssos{ 592144330Ssos struct ast_softc *stp = device_get_ivars(dev); 59351520Ssos int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0, 59451520Ssos 0, 0, 0, 0, 0, 0, 0, 0 }; 59566070Ssos int error; 59651520Ssos 597119404Ssos if ((function & ATAPI_SS_EJECT) && !stp->cap.eject) 59851520Ssos return 0; 599145713Ssos error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10); 60051520Ssos if (error) 60152067Ssos return error; 602166909Sjhb pause("astlu", 1 * hz); 603119404Ssos if (function == ATAPI_SS_EJECT) 60451520Ssos return 0; 605144330Ssos return ast_wait_dsc(dev, 60*60); 60651520Ssos} 60751520Ssos 60866070Ssosstatic int 609144330Ssosast_rewind(device_t dev) 61044380Ssos{ 61182053Ssos int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0, 61251520Ssos 0, 0, 0, 0, 0, 0, 0, 0 }; 61366070Ssos int error; 61444380Ssos 615145713Ssos error = ata_atapicmd(dev, ccb, NULL, 0, 0, 10); 61651520Ssos if (error) 61752067Ssos return error; 618144330Ssos return ast_wait_dsc(dev, 60*60); 61944380Ssos} 62044380Ssos 62166070Ssosstatic int 622144330Ssosast_erase(device_t dev) 62351520Ssos{ 62451520Ssos int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0, 62551520Ssos 0, 0, 0, 0, 0, 0, 0, 0 }; 62666070Ssos int error; 62751520Ssos 628144330Ssos if ((error = ast_rewind(dev))) 62951520Ssos return error; 63051520Ssos 631145713Ssos return ata_atapicmd(dev, ccb, NULL, 0, 0, 60*60); 63251520Ssos} 633119404Ssos 634119404Ssosstatic int 635144330Ssosast_test_ready(device_t dev) 636119404Ssos{ 637119404Ssos int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 638119404Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 639119404Ssos 640145713Ssos return ata_atapicmd(dev, ccb, NULL, 0, 0, 30); 641119404Ssos} 642119404Ssos 643119404Ssosstatic int 644144330Ssosast_wait_dsc(device_t dev, int timeout) 645119404Ssos{ 646119404Ssos int error = 0; 647119404Ssos int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0, 648119404Ssos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 649119404Ssos 650119404Ssos timeout *= hz; 651119404Ssos while (timeout > 0) { 652145713Ssos error = ata_atapicmd(dev, ccb, NULL, 0, 0, 0); 653119404Ssos if (error != EBUSY) 654119404Ssos break; 655166909Sjhb pause("atpwt", hz / 2); 656119404Ssos timeout -= (hz / 2); 657119404Ssos } 658119404Ssos return error; 659119404Ssos} 660144330Ssos 661144330Ssosstatic void 662144330Ssosast_describe(device_t dev) 663144330Ssos{ 664144330Ssos struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 665144330Ssos struct ata_device *atadev = device_get_softc(dev); 666144330Ssos struct ast_softc *stp = device_get_ivars(dev); 667144330Ssos 668144330Ssos if (bootverbose) { 669144330Ssos device_printf(dev, "<%.40s/%.8s> tape drive at ata%d as %s\n", 670144330Ssos atadev->param.model, atadev->param.revision, 671178067Ssos device_get_unit(ch->dev), ata_unit2str(atadev)); 672144330Ssos device_printf(dev, "%dKB/s, ", stp->cap.max_speed); 673144330Ssos printf("transfer limit %d blk%s, ", 674144330Ssos stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : ""); 675144330Ssos printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024); 676200171Smav printf("%s %s\n", ata_mode2str(atadev->mode), 677200171Smav ata_satarev2str(ATA_GETREV(device_get_parent(dev), atadev->unit))); 678144330Ssos device_printf(dev, "Medium: "); 679144330Ssos switch (stp->cap.medium_type) { 680144330Ssos case 0x00: 681144330Ssos printf("none"); break; 682144330Ssos case 0x17: 683144330Ssos printf("Travan 1 (400 Mbyte)"); break; 684144330Ssos case 0xb6: 685144330Ssos printf("Travan 4 (4 Gbyte)"); break; 686144330Ssos case 0xda: 687144330Ssos printf("OnStream ADR (15Gyte)"); break; 688144330Ssos default: 689144330Ssos printf("unknown (0x%x)", stp->cap.medium_type); 690144330Ssos } 691144330Ssos if (stp->cap.readonly) printf(", readonly"); 692144330Ssos if (stp->cap.reverse) printf(", reverse"); 693144330Ssos if (stp->cap.eformat) printf(", eformat"); 694144330Ssos if (stp->cap.qfa) printf(", qfa"); 695144330Ssos if (stp->cap.lock) printf(", lock"); 696144330Ssos if (stp->cap.locked) printf(", locked"); 697144330Ssos if (stp->cap.prevent) printf(", prevent"); 698144330Ssos if (stp->cap.eject) printf(", eject"); 699144330Ssos if (stp->cap.disconnect) printf(", disconnect"); 700144330Ssos if (stp->cap.ecc) printf(", ecc"); 701144330Ssos if (stp->cap.compress) printf(", compress"); 702144330Ssos if (stp->cap.blk512) printf(", 512b"); 703144330Ssos if (stp->cap.blk1024) printf(", 1024b"); 704144330Ssos if (stp->cap.blk32k) printf(", 32kb"); 705144330Ssos printf("\n"); 706144330Ssos } 707144330Ssos else { 708200171Smav device_printf(dev, "TAPE <%.40s/%.8s> at ata%d-%s %s %s\n", 709144330Ssos atadev->param.model, atadev->param.revision, 710178067Ssos device_get_unit(ch->dev), ata_unit2str(atadev), 711200171Smav ata_mode2str(atadev->mode), 712200171Smav ata_satarev2str(ATA_GETREV(device_get_parent(dev), atadev->unit))); 713144330Ssos } 714144330Ssos} 715144330Ssos 716144330Ssosstatic device_method_t ast_methods[] = { 717144330Ssos /* device interface */ 718144330Ssos DEVMETHOD(device_probe, ast_probe), 719144330Ssos DEVMETHOD(device_attach, ast_attach), 720144330Ssos DEVMETHOD(device_detach, ast_detach), 721144330Ssos DEVMETHOD(device_shutdown, ast_shutdown), 722144330Ssos 723144330Ssos /* ATA methods */ 724144330Ssos DEVMETHOD(ata_reinit, ast_reinit), 725144330Ssos 726233717Smarius DEVMETHOD_END 727144330Ssos}; 728144330Ssos 729144330Ssosstatic driver_t ast_driver = { 730144330Ssos "ast", 731144330Ssos ast_methods, 732144397Ssos 0, 733144330Ssos}; 734144330Ssos 735144330Ssosstatic devclass_t ast_devclass; 736144330Ssos 737145102SsosDRIVER_MODULE(ast, ata, ast_driver, ast_devclass, NULL, NULL); 738144330SsosMODULE_VERSION(ast, 1); 739144330SsosMODULE_DEPEND(ast, ata, 1, 1, 1); 740