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 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
));
158 ata_free_name(atadev
);
159 ata_free_lun(&ast_lun_map
, stp
->lun
);
161 atadev
->driver
= NULL
;
165 ast_sense(struct ast_softc
*stp
)
167 int count
, error
= 0;
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
)))) {
174 stp
->blksize
= 32768;
175 if (stp
->cap
.blk1024
)
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
);
193 ast_describe(struct ast_softc
*stp
)
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
);
201 kprintf("transfer limit %d blk%s, ",
202 stp
->cap
.ctl
, (stp
->cap
.ctl
> 1) ? "s" : "");
203 kprintf("%dKB buffer, ", (stp
->cap
.buffer_size
* DEV_BSIZE
) / 1024);
204 kprintf("%s\n", ata_mode2str(stp
->device
->mode
));
205 ata_prtdev(stp
->device
, "Medium: ");
206 switch (stp
->cap
.medium_type
) {
208 kprintf("none"); break;
210 kprintf("Travan 1 (400 Mbyte)"); break;
212 kprintf("Travan 4 (4 Gbyte)"); break;
214 kprintf("OnStream ADR (15Gyte)"); break;
216 kprintf("unknown (0x%x)", stp
->cap
.medium_type
);
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");
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
));
244 astopen(struct dev_open_args
*ap
)
246 cdev_t dev
= ap
->a_head
.a_dev
;
247 struct ast_softc
*stp
= dev
->si_drv1
;
252 if (count_dev(dev
) > 1)
255 atapi_test_ready(stp
->device
);
258 ast_prevent_allow(stp
, 1);
261 ata_prtdev(stp
->device
, "sense media type failed\n");
263 stp
->device
->flags
&= ~ATA_D_MEDIA_CHANGED
;
264 stp
->flags
&= ~(F_DATA_WRITTEN
| F_FM_WRITTEN
);
270 astclose(struct dev_close_args
*ap
)
272 cdev_t dev
= ap
->a_head
.a_dev
;
273 struct ast_softc
*stp
= dev
->si_drv1
;
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);
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
);
284 /* if minor is even rewind on close */
285 if (!(minor(dev
) & 0x01))
288 if (stp
->cap
.lock
&& count_dev(dev
) == 1)
289 ast_prevent_allow(stp
, 0);
291 stp
->flags
&= F_CTL_WARN
;
293 ata_prtdev(stp
->device
, "%llu total bytes transferred\n", ast_total
);
299 astioctl(struct dev_ioctl_args
*ap
)
301 cdev_t dev
= ap
->a_head
.a_dev
;
302 struct ast_softc
*stp
= dev
->si_drv1
;
308 struct mtget
*g
= (struct mtget
*) ap
->a_data
;
310 bzero(g
, sizeof(struct mtget
));
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;
326 struct mtop
*mt
= (struct mtop
*)ap
->a_data
;
328 switch ((int16_t) (mt
->mt_op
)) {
331 for (i
=0; i
< mt
->mt_count
&& !error
; i
++)
332 error
= ast_write_filemark(stp
, WF_WRITE
);
337 error
= ast_space(stp
, SP_FM
, mt
->mt_count
);
342 error
= ast_space(stp
, SP_FM
, -(mt
->mt_count
));
346 error
= ast_rewind(stp
);
350 error
= ast_load_unload(stp
, SS_EJECT
);
354 error
= ast_write_filemark(stp
, 0);
358 error
= ast_erase(stp
);
362 error
= ast_space(stp
, SP_EOD
, 0);
366 error
= ast_load_unload(stp
, SS_RETENSION
| SS_LOAD
);
383 struct ast_readposition position
;
385 if ((error
= ast_read_position(stp
, 0, &position
)))
387 *(u_int32_t
*)ap
->a_data
= position
.tape
;
392 struct ast_readposition position
;
394 if ((error
= ast_read_position(stp
, 1, &position
)))
396 *(u_int32_t
*)ap
->a_data
= position
.tape
;
400 error
= ast_locate(stp
, 0, *(u_int32_t
*)ap
->a_data
);
403 error
= ast_locate(stp
, 1, *(u_int32_t
*)ap
->a_data
);
412 aststrategy(struct dev_strategy_args
*ap
)
414 cdev_t dev
= ap
->a_head
.a_dev
;
415 struct bio
*bio
= ap
->a_bio
;
416 struct buf
*bp
= bio
->bio_buf
;
417 struct ast_softc
*stp
= dev
->si_drv1
;
419 if (stp
->device
->flags
& ATA_D_DETACHING
) {
420 bp
->b_flags
|= B_ERROR
;
426 /* if it's a null transfer, return immediatly. */
427 if (bp
->b_bcount
== 0) {
432 if (bp
->b_cmd
!= BUF_CMD_READ
&& (stp
->flags
& F_WRITEPROTECT
)) {
433 bp
->b_flags
|= B_ERROR
;
439 /* check for != blocksize requests */
440 if (bp
->b_bcount
% stp
->blksize
) {
441 ata_prtdev(stp
->device
, "transfers must be multiple of %d\n",
443 bp
->b_flags
|= B_ERROR
;
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) {
452 ata_prtdev(stp
->device
, "WARNING: CTL exceeded %d > %d\n",
453 bp
->b_bcount
, stp
->blksize
* stp
->cap
.ctl
);
454 stp
->flags
|= F_CTL_WARN
;
459 bioq_insert_tail(&stp
->bio_queue
, bio
);
461 ata_start(stp
->device
->channel
);
466 ast_start(struct ata_device
*atadev
)
468 struct ast_softc
*stp
= atadev
->driver
;
469 struct bio
*bio
= bioq_first(&stp
->bio_queue
);
476 bzero(ccb
, sizeof(ccb
));
479 if (bp
->b_cmd
== BUF_CMD_READ
)
482 ccb
[0] = ATAPI_WRITE
;
484 bioq_remove(&stp
->bio_queue
, bio
);
485 blkcount
= bp
->b_bcount
/ stp
->blksize
;
488 ccb
[2] = blkcount
>>16;
489 ccb
[3] = blkcount
>>8;
492 devstat_start_transaction(&stp
->stats
);
494 atapi_queue_cmd(stp
->device
, ccb
, bp
->b_data
, blkcount
* stp
->blksize
,
495 ((bp
->b_cmd
== BUF_CMD_READ
) ? ATPR_F_READ
: 0),
500 ast_done(struct atapi_request
*request
)
502 struct bio
*bio
= request
->driver
;
503 struct buf
*bp
= bio
->bio_buf
;
504 struct ast_softc
*stp
= request
->device
->driver
;
506 if (request
->error
) {
507 bp
->b_error
= request
->error
;
508 bp
->b_flags
|= B_ERROR
;
510 if (bp
->b_cmd
!= BUF_CMD_READ
)
511 stp
->flags
|= F_DATA_WRITTEN
;
512 bp
->b_resid
= bp
->b_bcount
- request
->donecount
;
513 ast_total
+= (bp
->b_bcount
- bp
->b_resid
);
515 devstat_end_transaction_buf(&stp
->stats
, bp
);
521 ast_mode_sense(struct ast_softc
*stp
, int page
, void *pagebuf
, int pagesize
)
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 };
527 error
= atapi_queue_cmd(stp
->device
, ccb
, pagebuf
, pagesize
, ATPR_F_READ
,
530 atapi_dump("ast: mode sense ", pagebuf
, pagesize
);
536 ast_mode_select(struct ast_softc
*stp
, void *pagebuf
, int pagesize
)
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 };
542 ata_prtdev(stp
->device
, "modeselect pagesize=%d\n", pagesize
);
543 atapi_dump("mode select ", pagebuf
, pagesize
);
545 return atapi_queue_cmd(stp
->device
, ccb
, pagebuf
, pagesize
, 0,
550 ast_write_filemark(struct ast_softc
*stp
, u_int8_t function
)
552 int8_t ccb
[16] = { ATAPI_WEOF
, 0x01, 0, 0, function
, 0, 0, 0,
553 0, 0, 0, 0, 0, 0, 0, 0 };
556 if (stp
->flags
& F_ONSTREAM
)
557 ccb
[4] = 0x00; /* only flush buffers supported */
560 if (stp
->flags
& F_FM_WRITTEN
)
561 stp
->flags
&= ~F_DATA_WRITTEN
;
563 stp
->flags
|= F_FM_WRITTEN
;
566 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
569 return atapi_wait_dsc(stp
->device
, 10*60);
573 ast_read_position(struct ast_softc
*stp
, int hard
,
574 struct ast_readposition
*position
)
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 };
580 error
= atapi_queue_cmd(stp
->device
, ccb
, (caddr_t
)position
,
581 sizeof(struct ast_readposition
), ATPR_F_READ
, 10,
583 position
->tape
= ntohl(position
->tape
);
584 position
->host
= ntohl(position
->host
);
589 ast_space(struct ast_softc
*stp
, u_int8_t function
, int32_t count
)
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 };
594 return atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 60*60, NULL
, NULL
);
598 ast_locate(struct ast_softc
*stp
, int hard
, u_int32_t pos
)
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 };
605 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
608 return atapi_wait_dsc(stp
->device
, 60*60);
612 ast_prevent_allow(struct ast_softc
*stp
, int lock
)
614 int8_t ccb
[16] = { ATAPI_PREVENT_ALLOW
, 0, 0, 0, lock
,
615 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
617 return atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0,30, NULL
, NULL
);
621 ast_load_unload(struct ast_softc
*stp
, u_int8_t function
)
623 int8_t ccb
[16] = { ATAPI_START_STOP
, 0x01, 0, 0, function
, 0, 0, 0,
624 0, 0, 0, 0, 0, 0, 0, 0 };
627 if ((function
& SS_EJECT
) && !stp
->cap
.eject
)
629 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
632 tsleep((caddr_t
)&error
, 0, "astlu", 1 * hz
);
633 if (function
== SS_EJECT
)
635 return atapi_wait_dsc(stp
->device
, 60*60);
639 ast_rewind(struct ast_softc
*stp
)
641 int8_t ccb
[16] = { ATAPI_REZERO
, 0x01, 0, 0, 0, 0, 0, 0,
642 0, 0, 0, 0, 0, 0, 0, 0 };
645 error
= atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 10, NULL
, NULL
);
648 return atapi_wait_dsc(stp
->device
, 60*60);
652 ast_erase(struct ast_softc
*stp
)
654 int8_t ccb
[16] = { ATAPI_ERASE
, 3, 0, 0, 0, 0, 0, 0,
655 0, 0, 0, 0, 0, 0, 0, 0 };
658 if ((error
= ast_rewind(stp
)))
661 return atapi_queue_cmd(stp
->device
, ccb
, NULL
, 0, 0, 60*60, NULL
, NULL
);