Deleted Added
sdiff udiff text old ( 86014 ) new ( 90215 )
full compact
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.

--- 9 unchanged lines hidden (view full) ---

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: head/sys/dev/ata/atapi-tape.c 90215 2002-02-04 19:23:40Z sos $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/ata.h>
34#include <sys/kernel.h>
35#include <sys/conf.h>
36#include <sys/malloc.h>

--- 43 unchanged lines hidden (view full) ---

80static int ast_erase(struct ast_softc *);
81
82/* internal vars */
83static u_int32_t ast_lun_map = 0;
84static u_int64_t ast_total = 0;
85static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers");
86
87int
88astattach(struct ata_device *atadev)
89{
90 struct ast_softc *stp;
91 struct ast_readposition position;
92 dev_t dev;
93
94 stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO);
95 if (!stp) {
96 ata_prtdev(atadev, "out of memory\n");
97 return -1;
98 }
99
100 stp->device = atadev;
101 stp->lun = ata_get_lun(&ast_lun_map);
102 ata_set_name(atadev, "ast", stp->lun);
103 bioq_init(&stp->queue);
104
105 if (ast_sense(stp)) {
106 free(stp, M_AST);
107 return -1;
108 }
109
110 if (!strcmp(atadev->param->model, "OnStream DI-30")) {
111 struct ast_transferpage transfer;
112 struct ast_identifypage identify;
113
114 stp->flags |= F_ONSTREAM;
115 bzero(&transfer, sizeof(struct ast_transferpage));
116 ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE,
117 &transfer, sizeof(transfer));
118 bzero(&identify, sizeof(struct ast_identifypage));

--- 13 unchanged lines hidden (view full) ---

132 dev->si_drv1 = stp;
133 dev->si_iosize_max = 252 * DEV_BSIZE;
134 stp->dev1 = dev;
135 dev = make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0, 1),
136 UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun);
137 dev->si_drv1 = stp;
138 dev->si_iosize_max = 252 * DEV_BSIZE;
139 stp->dev2 = dev;
140 stp->device->flags |= ATA_D_MEDIA_CHANGED;
141 ast_describe(stp);
142 atadev->driver = stp;
143 return 0;
144}
145
146void
147astdetach(struct ata_device *atadev)
148{
149 struct ast_softc *stp = atadev->driver;
150 struct bio *bp;
151
152 while ((bp = bioq_first(&stp->queue))) {
153 bioq_remove(&stp->queue, bp);
154 biofinish(bp, NULL, ENXIO);
155 }
156 destroy_dev(stp->dev1);
157 destroy_dev(stp->dev2);
158 devstat_remove_entry(&stp->stats);
159 ata_free_name(atadev);
160 ata_free_lun(&ast_lun_map, stp->lun);
161 free(stp, M_AST);
162 atadev->driver = NULL;
163}
164
165static int
166ast_sense(struct ast_softc *stp)
167{
168 int count, error = 0;
169
170 /* get drive capabilities, some drives needs this repeated */

--- 18 unchanged lines hidden (view full) ---

189 }
190 return 1;
191}
192
193static void
194ast_describe(struct ast_softc *stp)
195{
196 if (bootverbose) {
197 ata_prtdev(stp->device, "<%.40s/%.8s> tape drive at ata%d as %s\n",
198 stp->device->param->model, stp->device->param->revision,
199 device_get_unit(stp->device->channel->dev),
200 (stp->device->unit == ATA_MASTER) ? "master" : "slave");
201 ata_prtdev(stp->device, "%dKB/s, ", stp->cap.max_speed);
202 printf("transfer limit %d blk%s, ",
203 stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : "");
204 printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024);
205 printf("%s\n", ata_mode2str(stp->device->mode));
206 ata_prtdev(stp->device, "Medium: ");
207 switch (stp->cap.medium_type) {
208 case 0x00:
209 printf("none"); break;
210 case 0x17:
211 printf("Travan 1 (400 Mbyte)"); break;
212 case 0xb6:
213 printf("Travan 4 (4 Gbyte)"); break;
214 case 0xda:

--- 13 unchanged lines hidden (view full) ---

228 if (stp->cap.ecc) printf(", ecc");
229 if (stp->cap.compress) printf(", compress");
230 if (stp->cap.blk512) printf(", 512b");
231 if (stp->cap.blk1024) printf(", 1024b");
232 if (stp->cap.blk32k) printf(", 32kb");
233 printf("\n");
234 }
235 else {
236 ata_prtdev(stp->device, "TAPE <%.40s> at ata%d-%s %s\n",
237 stp->device->param->model,
238 device_get_unit(stp->device->channel->dev),
239 (stp->device->unit == ATA_MASTER) ? "master" : "slave",
240 ata_mode2str(stp->device->mode));
241 }
242}
243
244static int
245astopen(dev_t dev, int flags, int fmt, struct thread *td)
246{
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
269static int
270astclose(dev_t dev, int flags, int fmt, struct thread *td)
271{

--- 12 unchanged lines hidden (view full) ---

284 if (!(minor(dev) & 0x01))
285 ast_rewind(stp);
286
287 if (stp->cap.lock && count_dev(dev) == 1)
288 ast_prevent_allow(stp, 0);
289
290 stp->flags &= F_CTL_WARN;
291#ifdef AST_DEBUG
292 ata_prtdev(stp->device, "%llu total bytes transferred\n", ast_total);
293#endif
294 return 0;
295}
296
297static int
298astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
299{
300 struct ast_softc *stp = dev->si_drv1;

--- 106 unchanged lines hidden (view full) ---

407}
408
409static void
410aststrategy(struct bio *bp)
411{
412 struct ast_softc *stp = bp->bio_dev->si_drv1;
413 int s;
414
415 if (stp->device->flags & ATA_D_DETACHING) {
416 biofinish(bp, NULL, ENXIO);
417 return;
418 }
419
420 /* if it's a null transfer, return immediatly. */
421 if (bp->bio_bcount == 0) {
422 bp->bio_resid = 0;
423 biodone(bp);
424 return;
425 }
426 if (!(bp->bio_cmd == BIO_READ) && stp->flags & F_WRITEPROTECT) {
427 biofinish(bp, NULL, EPERM);
428 return;
429 }
430
431 /* check for != blocksize requests */
432 if (bp->bio_bcount % stp->blksize) {
433 ata_prtdev(stp->device, "transfers must be multiple of %d\n",
434 stp->blksize);
435 biofinish(bp, NULL, EIO);
436 return;
437 }
438
439 /* warn about transfers bigger than the device suggests */
440 if (bp->bio_bcount > stp->blksize * stp->cap.ctl) {
441 if ((stp->flags & F_CTL_WARN) == 0) {
442 ata_prtdev(stp->device, "WARNING: CTL exceeded %ld>%d\n",
443 bp->bio_bcount, stp->blksize * stp->cap.ctl);
444 stp->flags |= F_CTL_WARN;
445 }
446 }
447
448 s = splbio();
449 bioq_insert_tail(&stp->queue, bp);
450 ata_start(stp->device->channel);
451 splx(s);
452}
453
454void
455ast_start(struct ata_device *atadev)
456{
457 struct ast_softc *stp = atadev->driver;
458 struct bio *bp = bioq_first(&stp->queue);
459 u_int32_t blkcount;
460 int8_t ccb[16];
461
462 if (!bp)
463 return;
464
465 bzero(ccb, sizeof(ccb));

--- 8 unchanged lines hidden (view full) ---

474
475 ccb[1] = 1;
476 ccb[2] = blkcount>>16;
477 ccb[3] = blkcount>>8;
478 ccb[4] = blkcount;
479
480 devstat_start_transaction(&stp->stats);
481
482 atapi_queue_cmd(stp->device, ccb, bp->bio_data, blkcount * stp->blksize,
483 (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0,
484 120, ast_done, bp);
485}
486
487static int
488ast_done(struct atapi_request *request)
489{
490 struct bio *bp = request->driver;
491 struct ast_softc *stp = request->device->driver;
492
493 if (request->error) {
494 bp->bio_error = request->error;
495 bp->bio_flags |= BIO_ERROR;
496 }
497 else {
498 if (!(bp->bio_cmd == BIO_READ))
499 stp->flags |= F_DATA_WRITTEN;
500 bp->bio_resid = bp->bio_bcount - request->donecount;
501 ast_total += (bp->bio_bcount - bp->bio_resid);
502 }
503 biofinish(bp, &stp->stats, 0);
504 return 0;
505}
506
507static int
508ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize)
509{
510 int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize,
511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
512 int error;
513
514 error = atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, ATPR_F_READ,
515 10, NULL, NULL);
516#ifdef AST_DEBUG
517 atapi_dump("ast: mode sense ", pagebuf, pagesize);
518#endif
519 return error;
520}
521
522static int
523ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize)
524{
525 int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize,
526 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
527
528#ifdef AST_DEBUG
529 ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize);
530 atapi_dump("mode select ", pagebuf, pagesize);
531#endif
532 return atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, 0,
533 10, NULL, NULL);
534}
535
536static int
537ast_write_filemark(struct ast_softc *stp, u_int8_t function)
538{
539 int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0,
540 0, 0, 0, 0, 0, 0, 0, 0 };
541 int error;
542
543 if (stp->flags & F_ONSTREAM)
544 ccb[4] = 0x00; /* only flush buffers supported */
545 else {
546 if (function) {
547 if (stp->flags & F_FM_WRITTEN)
548 stp->flags &= ~F_DATA_WRITTEN;
549 else
550 stp->flags |= F_FM_WRITTEN;
551 }
552 }
553 error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
554 if (error)
555 return error;
556 return atapi_wait_dsc(stp->device, 10*60);
557}
558
559static int
560ast_read_position(struct ast_softc *stp, int hard,
561 struct ast_readposition *position)
562{
563 int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0,
564 0, 0, 0, 0, 0, 0, 0, 0 };
565 int error;
566
567 error = atapi_queue_cmd(stp->device, ccb, (caddr_t)position,
568 sizeof(struct ast_readposition), ATPR_F_READ, 10,
569 NULL, NULL);
570 position->tape = ntohl(position->tape);
571 position->host = ntohl(position->host);
572 return error;
573}
574
575static int
576ast_space(struct ast_softc *stp, u_int8_t function, int32_t count)
577{
578 int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count,
579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
580
581 return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL);
582}
583
584static int
585ast_locate(struct ast_softc *stp, int hard, u_int32_t pos)
586{
587 int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0,
588 pos>>24, pos>>16, pos>>8, pos,
589 0, 0, 0, 0, 0, 0, 0, 0, 0 };
590 int error;
591
592 error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
593 if (error)
594 return error;
595 return atapi_wait_dsc(stp->device, 60*60);
596}
597
598static int
599ast_prevent_allow(struct ast_softc *stp, int lock)
600{
601 int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
602 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
603
604 return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0,30, NULL, NULL);
605}
606
607static int
608ast_load_unload(struct ast_softc *stp, u_int8_t function)
609{
610 int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0,
611 0, 0, 0, 0, 0, 0, 0, 0 };
612 int error;
613
614 if ((function & SS_EJECT) && !stp->cap.eject)
615 return 0;
616 error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
617 if (error)
618 return error;
619 tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz);
620 if (function == SS_EJECT)
621 return 0;
622 return atapi_wait_dsc(stp->device, 60*60);
623}
624
625static int
626ast_rewind(struct ast_softc *stp)
627{
628 int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0,
629 0, 0, 0, 0, 0, 0, 0, 0 };
630 int error;
631
632 error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
633 if (error)
634 return error;
635 return atapi_wait_dsc(stp->device, 60*60);
636}
637
638static int
639ast_erase(struct ast_softc *stp)
640{
641 int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0,
642 0, 0, 0, 0, 0, 0, 0, 0 };
643 int error;
644
645 if ((error = ast_rewind(stp)))
646 return error;
647
648 return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL);
649}