2 * Copyright (c) 1998,1999,2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 * $FreeBSD: src/sys/dev/ata/atapi-tape.c,v 1.36.2.12 2002/07/31 11:19:26 sos Exp $
29 * $DragonFly: src/sys/dev/disk/ata/atapi-tape.c,v 1.22 2008/01/06 16:55:49 swildner Exp $
33 #include <sys/param.h>
34 #include <sys/systm.h>
36 #include <sys/kernel.h>
38 #include <sys/malloc.h>
42 #include <sys/diskslice.h>
43 #include <sys/devicestat.h>
46 #include <sys/thread2.h>
49 #include "atapi-all.h"
50 #include "atapi-tape.h"
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
;
58 static struct dev_ops ast_ops
= {
59 { "ast", 119, D_TAPE
| D_TRACKCLOSE
},
65 .d_strategy
= aststrategy
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
*);
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");
89 astattach(struct ata_device
*atadev
)
91 struct ast_softc
*stp
;
92 struct ast_readposition position
;
95 stp
= kmalloc(sizeof(struct ast_softc
), M_AST
, M_WAITOK
| M_ZERO
);
98 stp
->lun
= ata_get_lun(&ast_lun_map
);
99 ata_set_name(atadev
, "ast", stp
->lun
);
100 bioq_init(&stp
->bio_queue
);
102 if (ast_sense(stp
)) {
107 if (!strcmp(atadev
->param
->model
, "OnStream DI-30")) {
108 struct ast_transferpage transfer
;
109 struct ast_identifypage identify
;
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
);
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
);
127 dev
= make_dev(&ast_ops
, dkmakeminor(stp
->lun
, 0, 0),
128 UID_ROOT
, GID_OPERATOR
, 0640, "ast%d", stp
->lun
);
130 dev
->si_iosize_max
= 256 * DEV_BSIZE
;
131 dev
= make_dev(&ast_ops
, dkmakeminor(stp
->lun
, 0, 1),
132 UID_ROOT
, GID_OPERATOR
, 0640, "nast%d", stp
->lun
);
134 dev
->si_iosize_max
= 256 * DEV_BSIZE
;
135 stp
->device
->flags
|= ATA_D_MEDIA_CHANGED
;
137 atadev
->driver
= stp
;
142 astdetach(struct ata_device
*atadev
)
144 struct ast_softc
*stp
= atadev
->driver
;
148 while ((bio
= bioq_first(&stp
->bio_queue
))) {
149 bioq_remove(&stp
->bio_queue
, bio
);
151 bp
->b_flags
|= B_ERROR
;
155 devstat_remove_entry(&stp
->stats
);
156 dev_ops_remove_minor(&ast_ops
,/* dkunitmask(), */dkmakeunit(stp
->lun
));
157 ata_free_name(atadev
);
158 ata_free_lun(&ast_lun_map
, stp
->lun
);
160 atadev
->driver
= NULL
;
164 ast_sense(struct ast_softc
*stp
)
166 int count
, error
= 0;
168 /* get drive capabilities, some drives needs this repeated */
169 for (count
= 0 ; count
< 5 ; count
++) {
170 if (!(error
= ast_mode_sense(stp
, ATAPI_TAPE_CAP_PAGE
,
171 &stp
->cap
, sizeof(stp
->cap
)))) {
173 stp
->blksize
= 32768;
174 if (stp
->cap
.blk1024
)
180 stp
->cap
.max_speed
= ntohs(stp
->cap
.max_speed
);
181 stp
->cap
.max_defects
= ntohs(stp
->cap
.max_defects
);
182 stp
->cap
.ctl
= ntohs(stp
->cap
.ctl
);
183 stp
->cap
.speed
= ntohs(stp
->cap
.speed
);
184 stp
->cap
.buffer_size
= ntohs(stp
->cap
.buffer_size
);
192 ast_describe(struct ast_softc
*stp
)
195 ata_prtdev(stp
->device
, "<%.40s/%.8s> tape drive at ata%d as %s\n",
196 stp
->device
->param
->model
, stp
->device
->param
->revision
,
197 device_get_unit(stp
->device
->channel
->dev
),
198 (stp
->device
->unit
== ATA_MASTER
) ? "master" : "slave");
199 ata_prtdev(stp
->device
, "%dKB/s, ", stp
->cap
.max_speed
);
200 kprintf("transfer limit %d blk%s, ",
201 stp
->cap
.ctl
, (stp
->cap
.ctl
> 1) ? "s" : "");
202 kprintf("%dKB buffer, ", (stp
->cap
.buffer_size
* DEV_BSIZE
) / 1024);
203 kprintf("%s\n", ata_mode2str(stp
->device
->mode
));
204 ata_prtdev(stp
->device
, "Medium: ");
205 switch (stp
->cap
.medium_type
) {
207 kprintf("none"); break;
209 kprintf("Travan 1 (400 Mbyte)"); break;
211 kprintf("Travan 4 (4 Gbyte)"); break;
213 kprintf("OnStream ADR (15Gyte)"); break;
215 kprintf("unknown (0x%x)", stp
->cap
.medium_type
);
217 if (stp
->cap
.readonly
) kprintf(", readonly");
218 if (stp
->cap
.reverse
) kprintf(", reverse");
219 if (stp
->cap
.eformat
) kprintf(", eformat");
220 if (stp
->cap
.qfa
) kprintf(", qfa");
221 if (stp
->cap
.lock
) kprintf(", lock");
222 if (stp
->cap
.locked
) kprintf(", locked");
223 if (stp
->cap
.prevent
) kprintf(", prevent");
224 if (stp
->cap
.eject
) kprintf(", eject");
225 if (stp
->cap
.disconnect
) kprintf(", disconnect");
226 if (stp
->cap
.ecc
) kprintf(", ecc");
227 if (stp
->cap
.compress
) kprintf(", compress");
228 if (stp
->cap
.blk512
) kprintf(", 512b");
229 if (stp
->cap
.blk1024
) kprintf(", 1024b");
230 if (stp
->cap
.blk32k
) kprintf(", 32kb");
234 ata_prtdev(stp
->device
, "TAPE <%.40s> at ata%d-%s %s\n",
235 stp
->device
->param
->model
,
236 device_get_unit(stp
->device
->channel
->dev
),
237 (stp
->device
->unit
== ATA_MASTER
) ? "master" : "slave",
238 ata_mode2str(stp
->device
->mode
));
243 astopen(struct dev_open_args
*ap
)
245 cdev_t dev
= ap
->a_head
.a_dev
;
246 struct ast_softc
*stp
= dev
->si_drv1
;
251 if (count_dev(dev
) > 1)
254 atapi_test_ready(stp
->device
);
257 ast_prevent_allow(stp
, 1);
260 ata_prtdev(stp
->device
, "sense media type failed\n");
262 stp
->device
->flags
&= ~ATA_D_MEDIA_CHANGED
;
263 stp
->flags
&= ~(F_DATA_WRITTEN
| F_FM_WRITTEN
);
269 astclose(struct dev_close_args
*ap
)
271 cdev_t dev
= ap
->a_head
.a_dev
;
272 struct ast_softc
*stp
= dev
->si_drv1
;
274 /* flush buffers, some drives fail here, they should report ctl = 0 */
275 if (stp
->cap
.ctl
&& (stp
->flags
& F_DATA_WRITTEN
))
276 ast_write_filemark(stp
, 0);
278 /* write filemark if data written to tape */
279 if (!(stp
->flags
& F_ONSTREAM
) &&
280 (stp
->flags
& (F_DATA_WRITTEN
| F_FM_WRITTEN
)) == F_DATA_WRITTEN
)
281 ast_write_filemark(stp
, WF_WRITE
);
283 /* if minor is even rewind on close */
284 if (!(minor(dev
) & 0x01))
287 if (stp
->cap
.lock
&& count_dev(dev
) == 1)
288 ast_prevent_allow(stp
, 0);
290 stp
->flags
&= F_CTL_WARN
;
292 ata_prtdev(stp
->device
, "%llu total bytes transferred\n", ast_total
);
298 astioctl(struct dev_ioctl_args
*ap
)
300 cdev_t dev
= ap
->a_head
.a_dev
;
301 struct ast_softc
*stp
= dev
->si_drv1
;
307 struct mtget
*g
= (struct mtget
*) ap
->a_data
;
309 bzero(g
, sizeof(struct mtget
));
312 g
->mt_blksiz
= stp
->blksize
;
313 g
->mt_comp
= stp
->cap
.compress
;
314 g
->mt_density0
= 0; g
->mt_density1
= 0;
315 g
->mt_density2
= 0; g
->mt_density3
= 0;
316 g
->mt_blksiz0
= 0; g
->mt_blksiz1
= 0;
317 g
->mt_blksiz2
= 0; g
->mt_blksiz3
= 0;
318 g
->mt_comp0
= 0; g
->mt_comp1
= 0;
319 g
->mt_comp2
= 0; g
->mt_comp3
= 0;
325 struct mtop
*mt
= (struct mtop
*)ap
->a_data
;
327 switch ((int16_t) (mt
->mt_op
)) {
330 for (i
=0; i
< mt
->mt_count
&& !error
; i
++)
331 error
= ast_write_filemark(stp
, WF_WRITE
);
336 error
= ast_space(stp
, SP_FM
, mt
->mt_count
);
341 error
= ast_space(stp
, SP_FM
, -(mt
->mt_count
));
345 error
= ast_rewind(stp
);
349 error
= ast_load_unload(stp
, SS_EJECT
);
353 error
= ast_write_filemark(stp
, 0);
357 error
= ast_erase(stp
);
361 error
= ast_space(stp
, SP_EOD
, 0);
365 error
= ast_load_unload(stp
, SS_RETENSION
| SS_LOAD
);
382 struct ast_readposition position
;
384 if ((error
= ast_read_position(stp
, 0, &position
)))
386 *(u_int32_t
*)ap
->a_data
= position
.tape
;
391 struct ast_readposition position
;
393 if ((error
= ast_read_position(stp
, 1, &position
)))
395 *(u_int32_t
*)ap
->a_data
= position
.tape
;
399 error
= ast_locate(stp
, 0, *(u_int32_t
*)ap
->a_data
);
402 error
= ast_locate(stp
, 1, *(u_int32_t
*)ap
->a_data
);
411 aststrategy(struct dev_strategy_args
*ap
)
413 cdev_t dev
= ap
->a_head
.a_dev
;
414 struct bio
*bio
= ap
->a_bio
;
415 struct buf
*bp
= bio
->bio_buf
;
416 struct ast_softc
*stp
= dev
->si_drv1
;
418 if (stp
->device
->flags
& ATA_D_DETACHING
) {
419 bp
->b_flags
|= B_ERROR
;
425 /* if it's a null transfer, return immediatly. */
426 if (bp
->b_bcount
== 0) {
431 if (bp
->b_cmd
!= BUF_CMD_READ
&& (stp
->flags
& F_WRITEPROTECT
)) {
432 bp
->b_flags
|= B_ERROR
;
438 /* check for != blocksize requests */
439 if (bp
->b_bcount
% stp
->blksize
) {
440 ata_prtdev(stp
->device
, "transfers must be multiple of %d\n",
442 bp
->b_flags
|= B_ERROR
;
448 /* warn about transfers bigger than the device suggests */
449 if (bp
->b_bcount
> stp
->blksize
* stp
->cap
.ctl
) {
450 if ((stp
->flags
& F_CTL_WARN
) == 0) {
451 ata_prtdev(stp
->device
, "WARNING: CTL exceeded %d > %d\n",
452 bp
->b_bcount
, stp
->blksize
* stp
->cap
.ctl
);
453 stp
->flags
|= F_CTL_WARN
;
458 bioq_insert_tail(&stp
->bio_queue
, bio
);
460 ata_start(stp
->device
->channel
);
465 ast_start(struct ata_device
*atadev
)
467 struct ast_softc
*stp
= atadev
->driver
;
468 struct bio
*bio
= bioq_first(&stp
->bio_queue
);
475 bzero(ccb
, sizeof(ccb
));
478 if (bp
->b_cmd
== BUF_CMD_READ
)
481 ccb
[0] = ATAPI_WRITE
;
483 bioq_remove(&stp
->bio_queue
, bio
);
484 blkcount
= bp
->b_bcount
/ stp
->blksize
;
487 ccb
[2] = blkcount
>>16;
488 ccb
[3] = blkcount
>>8;
491 devstat_start_transaction(&stp
->stats
);
493 atapi_queue_cmd(stp
->device
, ccb
, bp
->b_data
, blkcount
* stp
->blksize
,
494 ((bp
->b_cmd
== BUF_CMD_READ
) ? ATPR_F_READ
: 0),
499 ast_done(struct atapi_request
*request
)
501 struct bio
*bio
= request
->driver
;
502 struct buf
*bp
= bio
->bio_buf
;
503 struct ast_softc
*stp
= request
->device
->driver
;
505 if (request
->error
) {
506 bp
->b_error
= request
->error
;
507 bp
->b_flags
|= B_ERROR
;
509 if (bp
->b_cmd
!= BUF_CMD_READ
)
510 stp
->flags
|= F_DATA_WRITTEN
;
511 bp
->b_resid
= bp
->b_bcount
- request
->donecount
;
512 ast_total
+= (bp
->b_bcount
- bp
->b_resid
);
514 devstat_end_transaction_buf(&stp
->stats
, bp
);
520 ast_mode_sense(struct ast_softc
*stp
, int page
, void *pagebuf
, int pagesize
)
522 int8_t ccb
[16] = { ATAPI_MODE_SENSE
, 0x08, page
, pagesize
>>8, pagesize
,
523 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
526 error
= atapi_queue_cmd(stp
->device
, ccb
, pagebuf
, pagesize
, ATPR_F_READ
,
529 atapi_dump("ast: mode sense ", pagebuf
, pagesize
);
535 ast_mode_select(struct ast_softc
*stp
, void *pagebuf
, int pagesize
)
537 int8_t ccb
[16] = { ATAPI_MODE_SELECT
, 0x10, 0, pagesize
>>8, pagesize
,
538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
541 ata_prtdev(stp
->device
, "modeselect pagesize=%d\n", pagesize
);
542 atapi_dump("mode select ", pagebuf
, pagesize
);
544 return atapi_queue_cmd(stp
->device
, ccb
, pagebuf
, pagesize
, 0,
549 ast_write_filemark(struct ast_softc
*stp
, u_int8_t function
)
551 int8_t ccb
[16] = { ATAPI_WEOF
, 0x01, 0, 0, function
, 0, 0, 0,
552 0, 0, 0, 0, 0, 0, 0, 0 };
555 if (stp
->flags
& F_ONSTREAM
)
556 ccb
[4] = 0x00; /* only flush buffers supported */
559 if (stp
->flags
& F_FM_WRITTEN
)
560 stp
->flags
&= ~F_DATA_WRITTEN
;
562 stp
->flags
|= F_FM_WRITTEN
;
565 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
568 return atapi_wait_dsc(stp
->device
, 10*60);
572 ast_read_position(struct ast_softc
*stp
, int hard
,
573 struct ast_readposition
*position
)
575 int8_t ccb
[16] = { ATAPI_READ_POSITION
, (hard
? 0x01 : 0), 0, 0, 0, 0, 0, 0,
576 0, 0, 0, 0, 0, 0, 0, 0 };
579 error
= atapi_queue_cmd(stp
->device
, ccb
, (caddr_t
)position
,
580 sizeof(struct ast_readposition
), ATPR_F_READ
, 10,
582 position
->tape
= ntohl(position
->tape
);
583 position
->host
= ntohl(position
->host
);
588 ast_space(struct ast_softc
*stp
, u_int8_t function
, int32_t count
)
590 int8_t ccb
[16] = { ATAPI_SPACE
, function
, count
>>16, count
>>8, count
,
591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
593 return atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 60*60, NULL
, NULL
);
597 ast_locate(struct ast_softc
*stp
, int hard
, u_int32_t pos
)
599 int8_t ccb
[16] = { ATAPI_LOCATE
, 0x01 | (hard
? 0x4 : 0), 0,
600 pos
>>24, pos
>>16, pos
>>8, pos
,
601 0, 0, 0, 0, 0, 0, 0, 0, 0 };
604 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
607 return atapi_wait_dsc(stp
->device
, 60*60);
611 ast_prevent_allow(struct ast_softc
*stp
, int lock
)
613 int8_t ccb
[16] = { ATAPI_PREVENT_ALLOW
, 0, 0, 0, lock
,
614 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
616 return atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0,30, NULL
, NULL
);
620 ast_load_unload(struct ast_softc
*stp
, u_int8_t function
)
622 int8_t ccb
[16] = { ATAPI_START_STOP
, 0x01, 0, 0, function
, 0, 0, 0,
623 0, 0, 0, 0, 0, 0, 0, 0 };
626 if ((function
& SS_EJECT
) && !stp
->cap
.eject
)
628 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
631 tsleep((caddr_t
)&error
, 0, "astlu", 1 * hz
);
632 if (function
== SS_EJECT
)
634 return atapi_wait_dsc(stp
->device
, 60*60);
638 ast_rewind(struct ast_softc
*stp
)
640 int8_t ccb
[16] = { ATAPI_REZERO
, 0x01, 0, 0, 0, 0, 0, 0,
641 0, 0, 0, 0, 0, 0, 0, 0 };
644 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
647 return atapi_wait_dsc(stp
->device
, 60*60);
651 ast_erase(struct ast_softc
*stp
)
653 int8_t ccb
[16] = { ATAPI_ERASE
, 3, 0, 0, 0, 0, 0, 0,
654 0, 0, 0, 0, 0, 0, 0, 0 };
657 if ((error
= ast_rewind(stp
)))
660 return atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 60*60, NULL
, NULL
);