1 /*-
2 * Copyright (c) 1998 - 2004 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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
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/bio.h>
40 #include <sys/bus.h>
41 #include <sys/mtio.h>
42 #include <sys/devicestat.h>
43 #include <sys/sema.h>
44 #include <sys/taskqueue.h>
45 #include <vm/uma.h>
46 #include <machine/bus.h>
47 #include <dev/ata/ata-all.h>
48 #include <dev/ata/atapi-tape.h>
49
50 /* device structures */
51 static d_open_t ast_open;
52 static d_close_t ast_close;
53 static d_ioctl_t ast_ioctl;
54 static d_strategy_t ast_strategy;
55 static struct cdevsw ast_cdevsw = {
56 .d_version = D_VERSION,
57 .d_open = ast_open,
58 .d_close = ast_close,
59 .d_read = physread,
60 .d_write = physwrite,
61 .d_ioctl = ast_ioctl,
62 .d_strategy = ast_strategy,
63 .d_name = "ast",
64 .d_flags = D_TAPE | D_TRACKCLOSE,
65 };
66
67 /* prototypes */
68 static void ast_detach(struct ata_device *);
69 static void ast_start(struct ata_device *);
70 static int ast_sense(struct ast_softc *);
71 static void ast_describe(struct ast_softc *);
72 static void ast_done(struct ata_request *);
73 static int ast_mode_sense(struct ast_softc *, int, void *, int);
74 static int ast_mode_select(struct ast_softc *, void *, int);
75 static int ast_write_filemark(struct ast_softc *, u_int8_t);
76 static int ast_read_position(struct ast_softc *, int, struct ast_readposition *);
77 static int ast_space(struct ast_softc *, u_int8_t, int32_t);
78 static int ast_locate(struct ast_softc *, int, u_int32_t);
79 static int ast_prevent_allow(struct ast_softc *stp, int);
80 static int ast_load_unload(struct ast_softc *, u_int8_t);
81 static int ast_rewind(struct ast_softc *);
82 static int ast_erase(struct ast_softc *);
83 static int ast_test_ready(struct ata_device *);
84 static int ast_wait_dsc(struct ata_device *, int);
85
86 /* internal vars */
87 static u_int32_t ast_lun_map = 0;
88 static u_int64_t ast_total = 0;
89 static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers");
90
91 void
92 ast_attach(struct ata_device *atadev)
93 {
94 struct ast_softc *stp;
95 struct ast_readposition position;
96 struct cdev *dev;
97
98 stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO);
99 if (!stp) {
100 ata_prtdev(atadev, "out of memory\n");
101 return;
102 }
103
104 stp->device = atadev;
105 stp->lun = ata_get_lun(&ast_lun_map);
106 ata_set_name(atadev, "ast", stp->lun);
107 bioq_init(&stp->queue);
108 mtx_init(&stp->queue_mtx, "ATAPI TAPE bioqueue lock", NULL, MTX_DEF);
109
110 if (ast_sense(stp)) {
111 free(stp, M_AST);
112 return;
113 }
114
115 if (!strcmp(atadev->param->model, "OnStream DI-30")) {
116 struct ast_transferpage transfer;
117 struct ast_identifypage identify;
118
119 stp->flags |= F_ONSTREAM;
120 bzero(&transfer, sizeof(struct ast_transferpage));
121 ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE,
122 &transfer, sizeof(transfer));
123 bzero(&identify, sizeof(struct ast_identifypage));
124 ast_mode_sense(stp, ATAPI_TAPE_IDENTIFY_PAGE,
125 &identify, sizeof(identify));
126 strncpy(identify.ident, "FBSD", 4);
127 ast_mode_select(stp, &identify, sizeof(identify));
128 ast_read_position(stp, 0, &position);
129 }
130
131 stp->stats = devstat_new_entry("ast", stp->lun, DEV_BSIZE,
132 DEVSTAT_NO_ORDERED_TAGS,
133 DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
134 DEVSTAT_PRIORITY_TAPE);
135 dev = make_dev(&ast_cdevsw, 2 * stp->lun,
136 UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun);
137 dev->si_drv1 = stp;
138 if (atadev->channel->dma)
139 dev->si_iosize_max = atadev->channel->dma->max_iosize;
140 else
141 dev->si_iosize_max = DFLTPHYS;
142 stp->dev1 = dev;
143 dev = make_dev(&ast_cdevsw, 2 * stp->lun + 1,
144 UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun);
145
146 dev->si_drv1 = stp;
147 if (atadev->channel->dma)
148 dev->si_iosize_max = atadev->channel->dma->max_iosize;
149 else
150 dev->si_iosize_max = DFLTPHYS;
151 stp->dev2 = dev;
152
153 /* setup the function ptrs */
154 atadev->detach = ast_detach;
155 atadev->start = ast_start;
156 atadev->softc = stp;
157 atadev->flags |= ATA_D_MEDIA_CHANGED;
158
159 /* announce we are here */
160 ast_describe(stp);
161 }
162
163 static void
164 ast_detach(struct ata_device *atadev)
165 {
166 struct ast_softc *stp = atadev->softc;
167
168 mtx_lock(&stp->queue_mtx);
169 bioq_flush(&stp->queue, NULL, ENXIO);
170 mtx_unlock(&stp->queue_mtx);
171 mtx_destroy(&stp->queue_mtx);
172 destroy_dev(stp->dev1);
173 destroy_dev(stp->dev2);
174 devstat_remove_entry(stp->stats);
175 ata_prtdev(atadev, "WARNING - removed from configuration\n");
176 ata_free_name(atadev);
177 ata_free_lun(&ast_lun_map, stp->lun);
178 atadev->attach = NULL;
179 atadev->detach = NULL;
180 atadev->start = NULL;
181 atadev->softc = NULL;
182 atadev->flags = 0;
183 free(stp, M_AST);
184 }
185
186 static int
187 ast_sense(struct ast_softc *stp)
188 {
189 int count;
190
191 /* get drive capabilities, some bugridden drives needs this repeated */
192 for (count = 0 ; count < 5 ; count++) {
193 if (!ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE,
194 &stp->cap, sizeof(stp->cap)) &&
195 stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) {
196 if (stp->cap.blk32k)
197 stp->blksize = 32768;
198 if (stp->cap.blk1024)
199 stp->blksize = 1024;
200 if (stp->cap.blk512)
201 stp->blksize = 512;
202 if (!stp->blksize)
203 continue;
204 stp->cap.max_speed = ntohs(stp->cap.max_speed);
205 stp->cap.max_defects = ntohs(stp->cap.max_defects);
206 stp->cap.ctl = ntohs(stp->cap.ctl);
207 stp->cap.speed = ntohs(stp->cap.speed);
208 stp->cap.buffer_size = ntohs(stp->cap.buffer_size);
209 return 0;
210 }
211 }
212 return 1;
213 }
214
215 static void
216 ast_describe(struct ast_softc *stp)
217 {
218 if (bootverbose) {
219 ata_prtdev(stp->device, "<%.40s/%.8s> tape drive at ata%d as %s\n",
220 stp->device->param->model, stp->device->param->revision,
221 device_get_unit(stp->device->channel->dev),
222 (stp->device->unit == ATA_MASTER) ? "master" : "slave");
223 ata_prtdev(stp->device, "%dKB/s, ", stp->cap.max_speed);
224 printf("transfer limit %d blk%s, ",
225 stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : "");
226 printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024);
227 printf("%s\n", ata_mode2str(stp->device->mode));
228 ata_prtdev(stp->device, "Medium: ");
229 switch (stp->cap.medium_type) {
230 case 0x00:
231 printf("none"); break;
232 case 0x17:
233 printf("Travan 1 (400 Mbyte)"); break;
234 case 0xb6:
235 printf("Travan 4 (4 Gbyte)"); break;
236 case 0xda:
237 printf("OnStream ADR (15Gyte)"); break;
238 default:
239 printf("unknown (0x%x)", stp->cap.medium_type);
240 }
241 if (stp->cap.readonly) printf(", readonly");
242 if (stp->cap.reverse) printf(", reverse");
243 if (stp->cap.eformat) printf(", eformat");
244 if (stp->cap.qfa) printf(", qfa");
245 if (stp->cap.lock) printf(", lock");
246 if (stp->cap.locked) printf(", locked");
247 if (stp->cap.prevent) printf(", prevent");
248 if (stp->cap.eject) printf(", eject");
249 if (stp->cap.disconnect) printf(", disconnect");
250 if (stp->cap.ecc) printf(", ecc");
251 if (stp->cap.compress) printf(", compress");
252 if (stp->cap.blk512) printf(", 512b");
253 if (stp->cap.blk1024) printf(", 1024b");
254 if (stp->cap.blk32k) printf(", 32kb");
255 printf("\n");
256 }
257 else {
258 ata_prtdev(stp->device, "TAPE <%.40s/%.8s> at ata%d-%s %s\n",
259 stp->device->param->model, stp->device->param->revision,
260 device_get_unit(stp->device->channel->dev),
261 (stp->device->unit == ATA_MASTER) ? "master" : "slave",
262 ata_mode2str(stp->device->mode));
263 }
264 }
265
266 static int
267 ast_open(struct cdev *dev, int flags, int fmt, struct thread *td)
268 {
269 struct ast_softc *stp = dev->si_drv1;
270
271 if (!stp || stp->device->flags & ATA_D_DETACHING)
272 return ENXIO;
273
274 if (count_dev(dev) > 1)
275 return EBUSY;
276
277 ast_test_ready(stp->device);
278
279 if (stp->cap.lock)
280 ast_prevent_allow(stp, 1);
281
282 if (ast_sense(stp))
283 ata_prtdev(stp->device, "sense media type failed\n");
284
285 stp->device->flags &= ~ATA_D_MEDIA_CHANGED;
286 stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN);
287 ast_total = 0;
288 return 0;
289 }
290
291 static int
292 ast_close(struct cdev *dev, int flags, int fmt, struct thread *td)
293 {
294 struct ast_softc *stp = dev->si_drv1;
295
296 /* flush buffers, some drives fail here, they should report ctl = 0 */
297 if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN))
298 ast_write_filemark(stp, 0);
299
300 /* write filemark if data written to tape */
301 if (!(stp->flags & F_ONSTREAM) &&
302 (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN)
303 ast_write_filemark(stp, ATAPI_WF_WRITE);
304
305 /* if minor is even rewind on close */
306 if (!(minor(dev) & 0x01))
307 ast_rewind(stp);
308
309 if (stp->cap.lock && count_dev(dev) == 1)
310 ast_prevent_allow(stp, 0);
311
312 stp->flags &= ~F_CTL_WARN;
313 #ifdef AST_DEBUG
314 ata_prtdev(stp->device, "%ju total bytes transferred\n",
315 (uintmax_t)ast_total);
316 #endif
317 return 0;
318 }
319
320 static int
321 ast_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
322 {
323 struct ast_softc *stp = dev->si_drv1;
324 int error = 0;
325
326 switch (cmd) {
327 case MTIOCGET:
328 {
329 struct mtget *g = (struct mtget *) addr;
330
331 bzero(g, sizeof(struct mtget));
332 g->mt_type = 7;
333 g->mt_density = 1;
334 g->mt_blksiz = stp->blksize;
335 g->mt_comp = stp->cap.compress;
336 g->mt_density0 = 0; g->mt_density1 = 0;
337 g->mt_density2 = 0; g->mt_density3 = 0;
338 g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
339 g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
340 g->mt_comp0 = 0; g->mt_comp1 = 0;
341 g->mt_comp2 = 0; g->mt_comp3 = 0;
342 }
343 break;
344
345 case MTIOCTOP:
346 {
347 int i;
348 struct mtop *mt = (struct mtop *)addr;
349
350 switch ((int16_t) (mt->mt_op)) {
351
352 case MTWEOF:
353 for (i=0; i < mt->mt_count && !error; i++)
354 error = ast_write_filemark(stp, ATAPI_WF_WRITE);
355 break;
356
357 case MTFSF:
358 if (mt->mt_count)
359 error = ast_space(stp, ATAPI_SP_FM, mt->mt_count);
360 break;
361
362 case MTBSF:
363 if (mt->mt_count)
364 error = ast_space(stp, ATAPI_SP_FM, -(mt->mt_count));
365 break;
366
367 case MTREW:
368 error = ast_rewind(stp);
369 break;
370
371 case MTOFFL:
372 error = ast_load_unload(stp, ATAPI_SS_EJECT);
373 break;
374
375 case MTNOP:
376 error = ast_write_filemark(stp, 0);
377 break;
378
379 case MTERASE:
380 error = ast_erase(stp);
381 break;
382
383 case MTEOD:
384 error = ast_space(stp, ATAPI_SP_EOD, 0);
385 break;
386
387 case MTRETENS:
388 error = ast_load_unload(stp, ATAPI_SS_RETENSION|ATAPI_SS_LOAD);
389 break;
390
391 case MTFSR:
392 case MTBSR:
393 case MTCACHE:
394 case MTNOCACHE:
395 case MTSETBSIZ:
396 case MTSETDNSTY:
397 case MTCOMP:
398 default:
399 error = EINVAL;
400 }
401 }
402 break;
403
404 case MTIOCRDSPOS:
405 {
406 struct ast_readposition position;
407
408 if ((error = ast_read_position(stp, 0, &position)))
409 break;
410 *(u_int32_t *)addr = position.tape;
411 }
412 break;
413
414 case MTIOCRDHPOS:
415 {
416 struct ast_readposition position;
417
418 if ((error = ast_read_position(stp, 1, &position)))
419 break;
420 *(u_int32_t *)addr = position.tape;
421 }
422 break;
423
424 case MTIOCSLOCATE:
425 error = ast_locate(stp, 0, *(u_int32_t *)addr);
426 break;
427
428 case MTIOCHLOCATE:
429 error = ast_locate(stp, 1, *(u_int32_t *)addr);
430 break;
431
432 default:
433 error = ENOTTY;
434 }
435 return error;
436 }
437
438 static void
439 ast_strategy(struct bio *bp)
440 {
441 struct ast_softc *stp = bp->bio_dev->si_drv1;
442
443 if (stp->device->flags & ATA_D_DETACHING) {
444 biofinish(bp, NULL, ENXIO);
445 return;
446 }
447
448 /* if it's a null transfer, return immediatly. */
449 if (bp->bio_bcount == 0) {
450 bp->bio_resid = 0;
451 biodone(bp);
452 return;
453 }
454 if (!(bp->bio_cmd == BIO_READ) && stp->flags & F_WRITEPROTECT) {
455 biofinish(bp, NULL, EPERM);
456 return;
457 }
458
459 /* check for != blocksize requests */
460 if (bp->bio_bcount % stp->blksize) {
461 ata_prtdev(stp->device, "transfers must be multiple of %d\n",
462 stp->blksize);
463 biofinish(bp, NULL, EIO);
464 return;
465 }
466
467 /* warn about transfers bigger than the device suggests */
468 if (bp->bio_bcount > stp->blksize * stp->cap.ctl) {
469 if ((stp->flags & F_CTL_WARN) == 0) {
470 ata_prtdev(stp->device, "WARNING: CTL exceeded %ld>%d\n",
471 bp->bio_bcount, stp->blksize * stp->cap.ctl);
472 stp->flags |= F_CTL_WARN;
473 }
474 }
475
476 mtx_lock(&stp->queue_mtx);
477 bioq_insert_tail(&stp->queue, bp);
478 mtx_unlock(&stp->queue_mtx);
479 ata_start(stp->device->channel);
480 }
481
482 static void
483 ast_start(struct ata_device *atadev)
484 {
485 struct ast_softc *stp = atadev->softc;
486 struct bio *bp;
487 struct ata_request *request;
488 u_int32_t blkcount;
489 int8_t ccb[16];
490
491 mtx_lock(&stp->queue_mtx);
492 bp = bioq_first(&stp->queue);
493 if (!bp) {
494 mtx_unlock(&stp->queue_mtx);
495 return;
496 }
497 bioq_remove(&stp->queue, bp);
498 mtx_unlock(&stp->queue_mtx);
499
500 bzero(ccb, sizeof(ccb));
501
502 if (bp->bio_cmd == BIO_READ)
503 ccb[0] = ATAPI_READ;
504 else
505 ccb[0] = ATAPI_WRITE;
506
507 blkcount = bp->bio_bcount / stp->blksize;
508
509 ccb[1] = 1;
510 ccb[2] = blkcount>>16;
511 ccb[3] = blkcount>>8;
512 ccb[4] = blkcount;
513
514 if (!(request = ata_alloc_request())) {
515 biofinish(bp, NULL, ENOMEM);
516 return;
517 }
518 request->device = atadev;
519 request->driver = bp;
520 bcopy(ccb, request->u.atapi.ccb,
521 (request->device->param->config & ATA_PROTO_MASK) ==
522 ATA_PROTO_ATAPI_12 ? 16 : 12);
523 request->data = bp->bio_data;
524 request->bytecount = blkcount * stp->blksize;
525 request->transfersize = min(request->bytecount, 65534);
526 request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 180 : 120;
527 request->retries = 2;
528 request->callback = ast_done;
529 switch (bp->bio_cmd) {
530 case BIO_READ:
531 request->flags |= (ATA_R_ATAPI | ATA_R_READ);
532 break;
533 case BIO_WRITE:
534 request->flags |= (ATA_R_ATAPI | ATA_R_WRITE);
535 break;
536 default:
537 ata_prtdev(atadev, "unknown BIO operation\n");
538 ata_free_request(request);
539 biofinish(bp, NULL, EIO);
540 return;
541 }
542 devstat_start_transaction_bio(stp->stats, bp);
543 ata_queue_request(request);
544 }
545
546 static void
547 ast_done(struct ata_request *request)
548 {
549 struct bio *bp = request->driver;
550 struct ast_softc *stp = request->device->softc;
551
552 /* finish up transfer */
553 if ((bp->bio_error = request->result))
554 bp->bio_flags |= BIO_ERROR;
555 if (bp->bio_cmd == BIO_WRITE)
556 stp->flags |= F_DATA_WRITTEN;
557 bp->bio_resid = bp->bio_bcount - request->donecount;
558 ast_total += (bp->bio_bcount - bp->bio_resid);
559 biofinish(bp, stp->stats, 0);
560 ata_free_request(request);
561 }
562
563 static int
564 ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize)
565 {
566 int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize,
567 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
568 int error;
569
570 error = ata_atapicmd(stp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10);
571 #ifdef AST_DEBUG
572 atapi_dump("ast: mode sense ", pagebuf, pagesize);
573 #endif
574 return error;
575 }
576
577 static int
578 ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize)
579 {
580 int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize,
581 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
582
583 #ifdef AST_DEBUG
584 ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize);
585 atapi_dump("mode select ", pagebuf, pagesize);
586 #endif
587 return ata_atapicmd(stp->device, ccb, pagebuf, pagesize, 0, 10);
588 }
589
590 static int
591 ast_write_filemark(struct ast_softc *stp, u_int8_t function)
592 {
593 int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0,
594 0, 0, 0, 0, 0, 0, 0, 0 };
595 int error;
596
597 if (stp->flags & F_ONSTREAM)
598 ccb[4] = 0x00; /* only flush buffers supported */
599 else {
600 if (function) {
601 if (stp->flags & F_FM_WRITTEN)
602 stp->flags &= ~F_DATA_WRITTEN;
603 else
604 stp->flags |= F_FM_WRITTEN;
605 }
606 }
607 error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
608 if (error)
609 return error;
610 return ast_wait_dsc(stp->device, 10*60);
611 }
612
613 static int
614 ast_read_position(struct ast_softc *stp, int hard,
615 struct ast_readposition *position)
616 {
617 int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0,
618 0, 0, 0, 0, 0, 0, 0, 0 };
619 int error;
620
621 error = ata_atapicmd(stp->device, ccb, (caddr_t)position,
622 sizeof(struct ast_readposition), ATA_R_READ, 10);
623 position->tape = ntohl(position->tape);
624 position->host = ntohl(position->host);
625 return error;
626 }
627
628 static int
629 ast_space(struct ast_softc *stp, u_int8_t function, int32_t count)
630 {
631 int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count,
632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
633
634 return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60);
635 }
636
637 static int
638 ast_locate(struct ast_softc *stp, int hard, u_int32_t pos)
639 {
640 int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0,
641 pos>>24, pos>>16, pos>>8, pos,
642 0, 0, 0, 0, 0, 0, 0, 0, 0 };
643 int error;
644
645 error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
646 if (error)
647 return error;
648 return ast_wait_dsc(stp->device, 60*60);
649 }
650
651 static int
652 ast_prevent_allow(struct ast_softc *stp, int lock)
653 {
654 int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
656
657 return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 30);
658 }
659
660 static int
661 ast_load_unload(struct ast_softc *stp, u_int8_t function)
662 {
663 int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0,
664 0, 0, 0, 0, 0, 0, 0, 0 };
665 int error;
666
667 if ((function & ATAPI_SS_EJECT) && !stp->cap.eject)
668 return 0;
669 error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
670 if (error)
671 return error;
672 tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz);
673 if (function == ATAPI_SS_EJECT)
674 return 0;
675 return ast_wait_dsc(stp->device, 60*60);
676 }
677
678 static int
679 ast_rewind(struct ast_softc *stp)
680 {
681 int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0,
682 0, 0, 0, 0, 0, 0, 0, 0 };
683 int error;
684
685 error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
686 if (error)
687 return error;
688 return ast_wait_dsc(stp->device, 60*60);
689 }
690
691 static int
692 ast_erase(struct ast_softc *stp)
693 {
694 int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0,
695 0, 0, 0, 0, 0, 0, 0, 0 };
696 int error;
697
698 if ((error = ast_rewind(stp)))
699 return error;
700
701 return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60);
702 }
703
704 static int
705 ast_test_ready(struct ata_device *atadev)
706 {
707 int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
708 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
709
710 return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
711 }
712
713 static int
714 ast_wait_dsc(struct ata_device *atadev, int timeout)
715 {
716 int error = 0;
717 int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0,
718 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
719
720 timeout *= hz;
721 while (timeout > 0) {
722 error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 0);
723 if (error != EBUSY)
724 break;
725 tsleep(&error, PRIBIO, "atpwt", hz / 2);
726 timeout -= (hz / 2);
727 }
728 return error;
729 }
Cache object: 4a7022ffc917dee175f83242dc70b056
|