| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 1998,1999,2000,2001,2002 Søren Schmidt <sos@FreeBSD.org> | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 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. | |
| 16 | * | |
| 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. | |
| 27 | * | |
| 28 | * $FreeBSD: src/sys/dev/ata/atapi-tape.c,v 1.36.2.12 2002/07/31 11:19:26 sos Exp $ | |
| 978400d3 | 29 | * $DragonFly: src/sys/dev/disk/ata/atapi-tape.c,v 1.22 2008/01/06 16:55:49 swildner Exp $ |
| 984263bc MD |
30 | */ |
| 31 | ||
| 32 | #include "opt_ata.h" | |
| 33 | #include <sys/param.h> | |
| 34 | #include <sys/systm.h> | |
| 35 | #include <sys/ata.h> | |
| 36 | #include <sys/kernel.h> | |
| 37 | #include <sys/conf.h> | |
| 38 | #include <sys/malloc.h> | |
| 39 | #include <sys/buf.h> | |
| 40 | #include <sys/bus.h> | |
| 41 | #include <sys/mtio.h> | |
| 5350e1e9 | 42 | #include <sys/diskslice.h> |
| 984263bc | 43 | #include <sys/devicestat.h> |
| 3020e3be MD |
44 | #include <sys/proc.h> |
| 45 | #include <sys/buf2.h> | |
| abe2ad7c | 46 | #include <sys/thread2.h> |
| 1f7ab7c9 | 47 | |
| 1f2de5d4 MD |
48 | #include "ata-all.h" |
| 49 | #include "atapi-all.h" | |
| 50 | #include "atapi-tape.h" | |
| 984263bc MD |
51 | |
| 52 | /* device structures */ | |
| 53 | static d_open_t astopen; | |
| 54 | static d_close_t astclose; | |
| 55 | static d_ioctl_t astioctl; | |
| 56 | static d_strategy_t aststrategy; | |
| fabb8ceb | 57 | |
| fef8985e MD |
58 | static struct dev_ops ast_ops = { |
| 59 | { "ast", 119, D_TAPE | D_TRACKCLOSE }, | |
| 60 | .d_open = astopen, | |
| 61 | .d_close = astclose, | |
| 62 | .d_read = physread, | |
| 63 | .d_write = physwrite, | |
| 64 | .d_ioctl = astioctl, | |
| 65 | .d_strategy = aststrategy | |
| 984263bc MD |
66 | }; |
| 67 | ||
| 68 | /* prototypes */ | |
| 69 | static int ast_sense(struct ast_softc *); | |
| 70 | static void ast_describe(struct ast_softc *); | |
| 71 | static int ast_done(struct atapi_request *); | |
| 72 | static int ast_mode_sense(struct ast_softc *, int, void *, int); | |
| 73 | static int ast_mode_select(struct ast_softc *, void *, int); | |
| 74 | static int ast_write_filemark(struct ast_softc *, u_int8_t); | |
| 75 | static int ast_read_position(struct ast_softc *, int, struct ast_readposition *); | |
| 76 | static int ast_space(struct ast_softc *, u_int8_t, int32_t); | |
| 77 | static int ast_locate(struct ast_softc *, int, u_int32_t); | |
| 78 | static int ast_prevent_allow(struct ast_softc *stp, int); | |
| 79 | static int ast_load_unload(struct ast_softc *, u_int8_t); | |
| 80 | static int ast_rewind(struct ast_softc *); | |
| 81 | static int ast_erase(struct ast_softc *); | |
| 82 | ||
| 83 | /* internal vars */ | |
| 84 | static u_int32_t ast_lun_map = 0; | |
| 85 | static u_int64_t ast_total = 0; | |
| 86 | static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers"); | |
| 87 | ||
| 88 | int | |
| 89 | astattach(struct ata_device *atadev) | |
| 90 | { | |
| 91 | struct ast_softc *stp; | |
| 92 | struct ast_readposition position; | |
| b13267a5 | 93 | cdev_t dev; |
| 984263bc | 94 | |
| efda3bd0 | 95 | stp = kmalloc(sizeof(struct ast_softc), M_AST, M_WAITOK | M_ZERO); |
| 984263bc MD |
96 | |
| 97 | stp->device = atadev; | |
| 98 | stp->lun = ata_get_lun(&ast_lun_map); | |
| 99 | ata_set_name(atadev, "ast", stp->lun); | |
| 81b5c339 | 100 | bioq_init(&stp->bio_queue); |
| 984263bc MD |
101 | |
| 102 | if (ast_sense(stp)) { | |
| efda3bd0 | 103 | kfree(stp, M_AST); |
| 984263bc MD |
104 | return 0; |
| 105 | } | |
| 106 | ||
| 107 | if (!strcmp(atadev->param->model, "OnStream DI-30")) { | |
| 108 | struct ast_transferpage transfer; | |
| 109 | struct ast_identifypage identify; | |
| 110 | ||
| 111 | stp->flags |= F_ONSTREAM; | |
| 112 | bzero(&transfer, sizeof(struct ast_transferpage)); | |
| 113 | ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE, | |
| 114 | &transfer, sizeof(transfer)); | |
| 115 | bzero(&identify, sizeof(struct ast_identifypage)); | |
| 116 | ast_mode_sense(stp, ATAPI_TAPE_IDENTIFY_PAGE, | |
| 117 | &identify, sizeof(identify)); | |
| 118 | strncpy(identify.ident, "FBSD", 4); | |
| 119 | ast_mode_select(stp, &identify, sizeof(identify)); | |
| 120 | ast_read_position(stp, 0, &position); | |
| 121 | } | |
| 122 | ||
| 123 | devstat_add_entry(&stp->stats, "ast", stp->lun, DEV_BSIZE, | |
| 124 | DEVSTAT_NO_ORDERED_TAGS, | |
| 125 | DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE, | |
| 126 | DEVSTAT_PRIORITY_TAPE); | |
| fef8985e | 127 | dev = make_dev(&ast_ops, dkmakeminor(stp->lun, 0, 0), |
| 984263bc MD |
128 | UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun); |
| 129 | dev->si_drv1 = stp; | |
| 130 | dev->si_iosize_max = 256 * DEV_BSIZE; | |
| fef8985e | 131 | dev = make_dev(&ast_ops, dkmakeminor(stp->lun, 0, 1), |
| 984263bc MD |
132 | UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun); |
| 133 | dev->si_drv1 = stp; | |
| 134 | dev->si_iosize_max = 256 * DEV_BSIZE; | |
| 984263bc MD |
135 | stp->device->flags |= ATA_D_MEDIA_CHANGED; |
| 136 | ast_describe(stp); | |
| 137 | atadev->driver = stp; | |
| 138 | return 1; | |
| 139 | } | |
| 140 | ||
| 141 | void | |
| 142 | astdetach(struct ata_device *atadev) | |
| 143 | { | |
| 144 | struct ast_softc *stp = atadev->driver; | |
| 145 | struct buf *bp; | |
| 81b5c339 | 146 | struct bio *bio; |
| 984263bc | 147 | |
| 81b5c339 MD |
148 | while ((bio = bioq_first(&stp->bio_queue))) { |
| 149 | bioq_remove(&stp->bio_queue, bio); | |
| 150 | bp = bio->bio_buf; | |
| 984263bc MD |
151 | bp->b_flags |= B_ERROR; |
| 152 | bp->b_error = ENXIO; | |
| 81b5c339 | 153 | biodone(bio); |
| 984263bc | 154 | } |
| 984263bc | 155 | devstat_remove_entry(&stp->stats); |
| cd29885a MD |
156 | kprintf("devfs: Please check that only the right atapi-tape device was removed!!\n"); |
| 157 | dev_ops_remove_minor(&ast_ops,/* dkunitmask(), */dkmakeunit(stp->lun)); | |
| 984263bc MD |
158 | ata_free_name(atadev); |
| 159 | ata_free_lun(&ast_lun_map, stp->lun); | |
| efda3bd0 | 160 | kfree(stp, M_AST); |
| 984263bc MD |
161 | atadev->driver = NULL; |
| 162 | } | |
| 163 | ||
| 164 | static int | |
| 165 | ast_sense(struct ast_softc *stp) | |
| 166 | { | |
| 167 | int count, error = 0; | |
| 168 | ||
| 169 | /* get drive capabilities, some drives needs this repeated */ | |
| 170 | for (count = 0 ; count < 5 ; count++) { | |
| 171 | if (!(error = ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE, | |
| 172 | &stp->cap, sizeof(stp->cap)))) { | |
| 173 | if (stp->cap.blk32k) | |
| 174 | stp->blksize = 32768; | |
| 175 | if (stp->cap.blk1024) | |
| 176 | stp->blksize = 1024; | |
| 177 | if (stp->cap.blk512) | |
| 178 | stp->blksize = 512; | |
| 179 | if (!stp->blksize) | |
| 180 | continue; | |
| 181 | stp->cap.max_speed = ntohs(stp->cap.max_speed); | |
| 182 | stp->cap.max_defects = ntohs(stp->cap.max_defects); | |
| 183 | stp->cap.ctl = ntohs(stp->cap.ctl); | |
| 184 | stp->cap.speed = ntohs(stp->cap.speed); | |
| 185 | stp->cap.buffer_size = ntohs(stp->cap.buffer_size); | |
| 186 | return 0; | |
| 187 | } | |
| 188 | } | |
| 189 | return 1; | |
| 190 | } | |
| 191 | ||
| 192 | static void | |
| 193 | ast_describe(struct ast_softc *stp) | |
| 194 | { | |
| 195 | if (bootverbose) { | |
| 196 | ata_prtdev(stp->device, "<%.40s/%.8s> tape drive at ata%d as %s\n", | |
| 197 | stp->device->param->model, stp->device->param->revision, | |
| 198 | device_get_unit(stp->device->channel->dev), | |
| 199 | (stp->device->unit == ATA_MASTER) ? "master" : "slave"); | |
| 200 | ata_prtdev(stp->device, "%dKB/s, ", stp->cap.max_speed); | |
| e3869ec7 | 201 | kprintf("transfer limit %d blk%s, ", |
| 984263bc | 202 | stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : ""); |
| e3869ec7 SW |
203 | kprintf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024); |
| 204 | kprintf("%s\n", ata_mode2str(stp->device->mode)); | |
| 984263bc MD |
205 | ata_prtdev(stp->device, "Medium: "); |
| 206 | switch (stp->cap.medium_type) { | |
| 207 | case 0x00: | |
| e3869ec7 | 208 | kprintf("none"); break; |
| 984263bc | 209 | case 0x17: |
| e3869ec7 | 210 | kprintf("Travan 1 (400 Mbyte)"); break; |
| 984263bc | 211 | case 0xb6: |
| e3869ec7 | 212 | kprintf("Travan 4 (4 Gbyte)"); break; |
| 984263bc | 213 | case 0xda: |
| e3869ec7 | 214 | kprintf("OnStream ADR (15Gyte)"); break; |
| 984263bc | 215 | default: |
| e3869ec7 | 216 | kprintf("unknown (0x%x)", stp->cap.medium_type); |
| 984263bc | 217 | } |
| e3869ec7 SW |
218 | if (stp->cap.readonly) kprintf(", readonly"); |
| 219 | if (stp->cap.reverse) kprintf(", reverse"); | |
| 220 | if (stp->cap.eformat) kprintf(", eformat"); | |
| 221 | if (stp->cap.qfa) kprintf(", qfa"); | |
| 222 | if (stp->cap.lock) kprintf(", lock"); | |
| 223 | if (stp->cap.locked) kprintf(", locked"); | |
| 224 | if (stp->cap.prevent) kprintf(", prevent"); | |
| 225 | if (stp->cap.eject) kprintf(", eject"); | |
| 226 | if (stp->cap.disconnect) kprintf(", disconnect"); | |
| 227 | if (stp->cap.ecc) kprintf(", ecc"); | |
| 228 | if (stp->cap.compress) kprintf(", compress"); | |
| 229 | if (stp->cap.blk512) kprintf(", 512b"); | |
| 230 | if (stp->cap.blk1024) kprintf(", 1024b"); | |
| 231 | if (stp->cap.blk32k) kprintf(", 32kb"); | |
| 232 | kprintf("\n"); | |
| 984263bc MD |
233 | } |
| 234 | else { | |
| 235 | ata_prtdev(stp->device, "TAPE <%.40s> at ata%d-%s %s\n", | |
| 236 | stp->device->param->model, | |
| 237 | device_get_unit(stp->device->channel->dev), | |
| 238 | (stp->device->unit == ATA_MASTER) ? "master" : "slave", | |
| 239 | ata_mode2str(stp->device->mode)); | |
| 240 | } | |
| 241 | } | |
| 242 | ||
| 243 | static int | |
| fef8985e | 244 | astopen(struct dev_open_args *ap) |
| 984263bc | 245 | { |
| b13267a5 | 246 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
247 | struct ast_softc *stp = dev->si_drv1; |
| 248 | ||
| 249 | if (!stp) | |
| 250 | return ENXIO; | |
| 251 | ||
| 252 | if (count_dev(dev) > 1) | |
| 253 | return EBUSY; | |
| 254 | ||
| 255 | atapi_test_ready(stp->device); | |
| 256 | ||
| 257 | if (stp->cap.lock) | |
| 258 | ast_prevent_allow(stp, 1); | |
| 259 | ||
| 260 | if (ast_sense(stp)) | |
| 261 | ata_prtdev(stp->device, "sense media type failed\n"); | |
| 262 | ||
| 263 | stp->device->flags &= ~ATA_D_MEDIA_CHANGED; | |
| 264 | stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN); | |
| 265 | ast_total = 0; | |
| 266 | return 0; | |
| 267 | } | |
| 268 | ||
| 269 | static int | |
| fef8985e | 270 | astclose(struct dev_close_args *ap) |
| 984263bc | 271 | { |
| b13267a5 | 272 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
273 | struct ast_softc *stp = dev->si_drv1; |
| 274 | ||
| 275 | /* flush buffers, some drives fail here, they should report ctl = 0 */ | |
| 276 | if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN)) | |
| 277 | ast_write_filemark(stp, 0); | |
| 278 | ||
| 279 | /* write filemark if data written to tape */ | |
| 280 | if (!(stp->flags & F_ONSTREAM) && | |
| 281 | (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN) | |
| 282 | ast_write_filemark(stp, WF_WRITE); | |
| 283 | ||
| 284 | /* if minor is even rewind on close */ | |
| 285 | if (!(minor(dev) & 0x01)) | |
| 286 | ast_rewind(stp); | |
| 287 | ||
| 288 | if (stp->cap.lock && count_dev(dev) == 1) | |
| 289 | ast_prevent_allow(stp, 0); | |
| 290 | ||
| 291 | stp->flags &= F_CTL_WARN; | |
| 292 | #ifdef AST_DEBUG | |
| 293 | ata_prtdev(stp->device, "%llu total bytes transferred\n", ast_total); | |
| 294 | #endif | |
| 295 | return 0; | |
| 296 | } | |
| 297 | ||
| 298 | static int | |
| fef8985e | 299 | astioctl(struct dev_ioctl_args *ap) |
| 984263bc | 300 | { |
| b13267a5 | 301 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
302 | struct ast_softc *stp = dev->si_drv1; |
| 303 | int error = 0; | |
| 304 | ||
| fef8985e | 305 | switch (ap->a_cmd) { |
| 984263bc MD |
306 | case MTIOCGET: |
| 307 | { | |
| fef8985e | 308 | struct mtget *g = (struct mtget *) ap->a_data; |
| 984263bc MD |
309 | |
| 310 | bzero(g, sizeof(struct mtget)); | |
| 311 | g->mt_type = 7; | |
| 312 | g->mt_density = 1; | |
| 313 | g->mt_blksiz = stp->blksize; | |
| 314 | g->mt_comp = stp->cap.compress; | |
| 315 | g->mt_density0 = 0; g->mt_density1 = 0; | |
| 316 | g->mt_density2 = 0; g->mt_density3 = 0; | |
| 317 | g->mt_blksiz0 = 0; g->mt_blksiz1 = 0; | |
| 318 | g->mt_blksiz2 = 0; g->mt_blksiz3 = 0; | |
| 319 | g->mt_comp0 = 0; g->mt_comp1 = 0; | |
| 320 | g->mt_comp2 = 0; g->mt_comp3 = 0; | |
| 321 | break; | |
| 322 | } | |
| 323 | case MTIOCTOP: | |
| 324 | { | |
| 325 | int i; | |
| fef8985e | 326 | struct mtop *mt = (struct mtop *)ap->a_data; |
| 984263bc MD |
327 | |
| 328 | switch ((int16_t) (mt->mt_op)) { | |
| 329 | ||
| 330 | case MTWEOF: | |
| 331 | for (i=0; i < mt->mt_count && !error; i++) | |
| 332 | error = ast_write_filemark(stp, WF_WRITE); | |
| 333 | break; | |
| 334 | ||
| 335 | case MTFSF: | |
| 336 | if (mt->mt_count) | |
| 337 | error = ast_space(stp, SP_FM, mt->mt_count); | |
| 338 | break; | |
| 339 | ||
| 340 | case MTBSF: | |
| 341 | if (mt->mt_count) | |
| 342 | error = ast_space(stp, SP_FM, -(mt->mt_count)); | |
| 343 | break; | |
| 344 | ||
| 345 | case MTREW: | |
| 346 | error = ast_rewind(stp); | |
| 347 | break; | |
| 348 | ||
| 349 | case MTOFFL: | |
| 350 | error = ast_load_unload(stp, SS_EJECT); | |
| 351 | break; | |
| 352 | ||
| 353 | case MTNOP: | |
| 354 | error = ast_write_filemark(stp, 0); | |
| 355 | break; | |
| 356 | ||
| 357 | case MTERASE: | |
| 358 | error = ast_erase(stp); | |
| 359 | break; | |
| 360 | ||
| 361 | case MTEOD: | |
| 362 | error = ast_space(stp, SP_EOD, 0); | |
| 363 | break; | |
| 364 | ||
| 365 | case MTRETENS: | |
| 366 | error = ast_load_unload(stp, SS_RETENSION | SS_LOAD); | |
| 367 | break; | |
| 368 | ||
| 369 | case MTFSR: | |
| 370 | case MTBSR: | |
| 371 | case MTCACHE: | |
| 372 | case MTNOCACHE: | |
| 373 | case MTSETBSIZ: | |
| 374 | case MTSETDNSTY: | |
| 375 | case MTCOMP: | |
| 376 | default: | |
| 377 | error = EINVAL; | |
| 378 | } | |
| 379 | break; | |
| 380 | } | |
| 381 | case MTIOCRDSPOS: | |
| 382 | { | |
| 383 | struct ast_readposition position; | |
| 384 | ||
| 385 | if ((error = ast_read_position(stp, 0, &position))) | |
| 386 | break; | |
| fef8985e | 387 | *(u_int32_t *)ap->a_data = position.tape; |
| 984263bc MD |
388 | break; |
| 389 | } | |
| 390 | case MTIOCRDHPOS: | |
| 391 | { | |
| 392 | struct ast_readposition position; | |
| 393 | ||
| 394 | if ((error = ast_read_position(stp, 1, &position))) | |
| 395 | break; | |
| fef8985e | 396 | *(u_int32_t *)ap->a_data = position.tape; |
| 984263bc MD |
397 | break; |
| 398 | } | |
| 399 | case MTIOCSLOCATE: | |
| fef8985e | 400 | error = ast_locate(stp, 0, *(u_int32_t *)ap->a_data); |
| 984263bc MD |
401 | break; |
| 402 | case MTIOCHLOCATE: | |
| fef8985e | 403 | error = ast_locate(stp, 1, *(u_int32_t *)ap->a_data); |
| 984263bc MD |
404 | break; |
| 405 | default: | |
| 406 | error = ENOTTY; | |
| 407 | } | |
| 408 | return error; | |
| 409 | } | |
| 410 | ||
| fef8985e MD |
411 | static int |
| 412 | aststrategy(struct dev_strategy_args *ap) | |
| 984263bc | 413 | { |
| b13267a5 | 414 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 415 | struct bio *bio = ap->a_bio; |
| 81b5c339 MD |
416 | struct buf *bp = bio->bio_buf; |
| 417 | struct ast_softc *stp = dev->si_drv1; | |
| 984263bc MD |
418 | |
| 419 | if (stp->device->flags & ATA_D_DETACHING) { | |
| 420 | bp->b_flags |= B_ERROR; | |
| 421 | bp->b_error = ENXIO; | |
| 81b5c339 | 422 | biodone(bio); |
| fef8985e | 423 | return(0); |
| 984263bc MD |
424 | } |
| 425 | ||
| 426 | /* if it's a null transfer, return immediatly. */ | |
| 427 | if (bp->b_bcount == 0) { | |
| 428 | bp->b_resid = 0; | |
| 81b5c339 | 429 | biodone(bio); |
| fef8985e | 430 | return(0); |
| 984263bc | 431 | } |
| 10f3fee5 | 432 | if (bp->b_cmd != BUF_CMD_READ && (stp->flags & F_WRITEPROTECT)) { |
| 984263bc MD |
433 | bp->b_flags |= B_ERROR; |
| 434 | bp->b_error = EPERM; | |
| 81b5c339 | 435 | biodone(bio); |
| fef8985e | 436 | return(0); |
| 984263bc MD |
437 | } |
| 438 | ||
| 439 | /* check for != blocksize requests */ | |
| 440 | if (bp->b_bcount % stp->blksize) { | |
| 441 | ata_prtdev(stp->device, "transfers must be multiple of %d\n", | |
| 442 | stp->blksize); | |
| 443 | bp->b_flags |= B_ERROR; | |
| 444 | bp->b_error = EIO; | |
| 81b5c339 | 445 | biodone(bio); |
| fef8985e | 446 | return(0); |
| 984263bc MD |
447 | } |
| 448 | ||
| 449 | /* warn about transfers bigger than the device suggests */ | |
| 450 | if (bp->b_bcount > stp->blksize * stp->cap.ctl) { | |
| 451 | if ((stp->flags & F_CTL_WARN) == 0) { | |
| 54078292 | 452 | ata_prtdev(stp->device, "WARNING: CTL exceeded %d > %d\n", |
| 984263bc MD |
453 | bp->b_bcount, stp->blksize * stp->cap.ctl); |
| 454 | stp->flags |= F_CTL_WARN; | |
| 455 | } | |
| 456 | } | |
| 457 | ||
| abe2ad7c | 458 | crit_enter(); |
| 81b5c339 | 459 | bioq_insert_tail(&stp->bio_queue, bio); |
| abe2ad7c | 460 | crit_exit(); |
| 984263bc | 461 | ata_start(stp->device->channel); |
| fef8985e | 462 | return(0); |
| 984263bc MD |
463 | } |
| 464 | ||
| 465 | void | |
| 466 | ast_start(struct ata_device *atadev) | |
| 467 | { | |
| 468 | struct ast_softc *stp = atadev->driver; | |
| 81b5c339 MD |
469 | struct bio *bio = bioq_first(&stp->bio_queue); |
| 470 | struct buf *bp; | |
| 984263bc MD |
471 | u_int32_t blkcount; |
| 472 | int8_t ccb[16]; | |
| 473 | ||
| 81b5c339 | 474 | if (bio == NULL) |
| 984263bc | 475 | return; |
| 984263bc MD |
476 | bzero(ccb, sizeof(ccb)); |
| 477 | ||
| 81b5c339 | 478 | bp = bio->bio_buf; |
| 10f3fee5 | 479 | if (bp->b_cmd == BUF_CMD_READ) |
| 984263bc MD |
480 | ccb[0] = ATAPI_READ; |
| 481 | else | |
| 482 | ccb[0] = ATAPI_WRITE; | |
| 483 | ||
| 81b5c339 | 484 | bioq_remove(&stp->bio_queue, bio); |
| 984263bc MD |
485 | blkcount = bp->b_bcount / stp->blksize; |
| 486 | ||
| 487 | ccb[1] = 1; | |
| 488 | ccb[2] = blkcount>>16; | |
| 489 | ccb[3] = blkcount>>8; | |
| 490 | ccb[4] = blkcount; | |
| 491 | ||
| 492 | devstat_start_transaction(&stp->stats); | |
| 493 | ||
| 494 | atapi_queue_cmd(stp->device, ccb, bp->b_data, blkcount * stp->blksize, | |
| 10f3fee5 | 495 | ((bp->b_cmd == BUF_CMD_READ) ? ATPR_F_READ : 0), |
| 81b5c339 | 496 | 120, ast_done, bio); |
| 984263bc MD |
497 | } |
| 498 | ||
| 499 | static int | |
| 500 | ast_done(struct atapi_request *request) | |
| 501 | { | |
| 81b5c339 MD |
502 | struct bio *bio = request->driver; |
| 503 | struct buf *bp = bio->bio_buf; | |
| 984263bc MD |
504 | struct ast_softc *stp = request->device->driver; |
| 505 | ||
| 506 | if (request->error) { | |
| 507 | bp->b_error = request->error; | |
| 508 | bp->b_flags |= B_ERROR; | |
| 81b5c339 | 509 | } else { |
| 10f3fee5 | 510 | if (bp->b_cmd != BUF_CMD_READ) |
| 984263bc MD |
511 | stp->flags |= F_DATA_WRITTEN; |
| 512 | bp->b_resid = bp->b_bcount - request->donecount; | |
| 513 | ast_total += (bp->b_bcount - bp->b_resid); | |
| 514 | } | |
| 515 | devstat_end_transaction_buf(&stp->stats, bp); | |
| 81b5c339 | 516 | biodone(bio); |
| 984263bc MD |
517 | return 0; |
| 518 | } | |
| 519 | ||
| 520 | static int | |
| 521 | ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize) | |
| 522 | { | |
| 523 | int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize, | |
| 524 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 525 | int error; | |
| 526 | ||
| 527 | error = atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, ATPR_F_READ, | |
| 528 | 10, NULL, NULL); | |
| 529 | #ifdef AST_DEBUG | |
| 530 | atapi_dump("ast: mode sense ", pagebuf, pagesize); | |
| 531 | #endif | |
| 532 | return error; | |
| 533 | } | |
| 534 | ||
| 535 | static int | |
| 536 | ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize) | |
| 537 | { | |
| 538 | int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize, | |
| 539 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 540 | ||
| 541 | #ifdef AST_DEBUG | |
| 542 | ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize); | |
| 543 | atapi_dump("mode select ", pagebuf, pagesize); | |
| 544 | #endif | |
| 545 | return atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, 0, | |
| 546 | 10, NULL, NULL); | |
| 547 | } | |
| 548 | ||
| 549 | static int | |
| 550 | ast_write_filemark(struct ast_softc *stp, u_int8_t function) | |
| 551 | { | |
| 552 | int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0, | |
| 553 | 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 554 | int error; | |
| 555 | ||
| 556 | if (stp->flags & F_ONSTREAM) | |
| 557 | ccb[4] = 0x00; /* only flush buffers supported */ | |
| 558 | else { | |
| 559 | if (function) { | |
| 560 | if (stp->flags & F_FM_WRITTEN) | |
| 561 | stp->flags &= ~F_DATA_WRITTEN; | |
| 562 | else | |
| 563 | stp->flags |= F_FM_WRITTEN; | |
| 564 | } | |
| 565 | } | |
| 566 | error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); | |
| 567 | if (error) | |
| 568 | return error; | |
| 569 | return atapi_wait_dsc(stp->device, 10*60); | |
| 570 | } | |
| 571 | ||
| 572 | static int | |
| 573 | ast_read_position(struct ast_softc *stp, int hard, | |
| 574 | struct ast_readposition *position) | |
| 575 | { | |
| 576 | int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0, | |
| 577 | 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 578 | int error; | |
| 579 | ||
| 580 | error = atapi_queue_cmd(stp->device, ccb, (caddr_t)position, | |
| 581 | sizeof(struct ast_readposition), ATPR_F_READ, 10, | |
| 582 | NULL, NULL); | |
| 583 | position->tape = ntohl(position->tape); | |
| 584 | position->host = ntohl(position->host); | |
| 585 | return error; | |
| 586 | } | |
| 587 | ||
| 588 | static int | |
| 589 | ast_space(struct ast_softc *stp, u_int8_t function, int32_t count) | |
| 590 | { | |
| 591 | int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count, | |
| 592 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 593 | ||
| 594 | return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL); | |
| 595 | } | |
| 596 | ||
| 597 | static int | |
| 598 | ast_locate(struct ast_softc *stp, int hard, u_int32_t pos) | |
| 599 | { | |
| 600 | int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0, | |
| 601 | pos>>24, pos>>16, pos>>8, pos, | |
| 602 | 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 603 | int error; | |
| 604 | ||
| 605 | error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); | |
| 606 | if (error) | |
| 607 | return error; | |
| 608 | return atapi_wait_dsc(stp->device, 60*60); | |
| 609 | } | |
| 610 | ||
| 611 | static int | |
| 612 | ast_prevent_allow(struct ast_softc *stp, int lock) | |
| 613 | { | |
| 614 | int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, | |
| 615 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 616 | ||
| 617 | return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0,30, NULL, NULL); | |
| 618 | } | |
| 619 | ||
| 620 | static int | |
| 621 | ast_load_unload(struct ast_softc *stp, u_int8_t function) | |
| 622 | { | |
| 623 | int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0, | |
| 624 | 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 625 | int error; | |
| 626 | ||
| 627 | if ((function & SS_EJECT) && !stp->cap.eject) | |
| 628 | return 0; | |
| 629 | error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); | |
| 630 | if (error) | |
| 631 | return error; | |
| 377d4740 | 632 | tsleep((caddr_t)&error, 0, "astlu", 1 * hz); |
| 984263bc MD |
633 | if (function == SS_EJECT) |
| 634 | return 0; | |
| 635 | return atapi_wait_dsc(stp->device, 60*60); | |
| 636 | } | |
| 637 | ||
| 638 | static int | |
| 639 | ast_rewind(struct ast_softc *stp) | |
| 640 | { | |
| 641 | int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0, | |
| 642 | 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 643 | int error; | |
| 644 | ||
| 645 | error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); | |
| 646 | if (error) | |
| 647 | return error; | |
| 648 | return atapi_wait_dsc(stp->device, 60*60); | |
| 649 | } | |
| 650 | ||
| 651 | static int | |
| 652 | ast_erase(struct ast_softc *stp) | |
| 653 | { | |
| 654 | int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0, | |
| 655 | 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| 656 | int error; | |
| 657 | ||
| 658 | if ((error = ast_rewind(stp))) | |
| 659 | return error; | |
| 660 | ||
| 661 | return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL); | |
| 662 | } |