2 * Copyright (c) 1998 Søren Schmidt
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/i386/isa/wst.c,v 1.28 2000/01/29 16:00:34 peter Exp $
29 * $DragonFly: src/sys/dev/disk/wst/Attic/wst.c,v 1.2 2003/06/17 04:28:37 dillon Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
39 #include <sys/malloc.h>
42 #include <machine/clock.h>
43 #include <i386/isa/atapi.h>
45 static d_open_t wstopen;
46 static d_close_t wstclose;
47 static d_ioctl_t wstioctl;
48 static d_strategy_t wststrategy;
52 static struct cdevsw wst_cdevsw = {
56 /* write */ physwrite,
60 /* strategy */ wststrategy,
69 static unsigned int wst_total = 0;
71 #define NUNIT (NWDC*2)
72 #define UNIT(d) ((minor(d) >> 3) & 3)
74 #define WST_OPEN 0x0001 /* The device is opened */
75 #define WST_MEDIA_CHANGED 0x0002 /* The media have changed */
76 #define WST_DATA_WRITTEN 0x0004 /* Data has been written */
77 #define WST_FM_WRITTEN 0x0008 /* Filemark has been written */
78 #define WST_DEBUG 0x0010 /* Print debug info */
79 #define WST_CTL_WARN 0x0020 /* Have we warned about CTL wrong? */
81 /* ATAPI tape commands not in std ATAPI command set */
82 #define ATAPI_TAPE_REWIND 0x01
83 #define ATAPI_TAPE_REQUEST_SENSE 0x03
84 #define ATAPI_TAPE_READ_CMD 0x08
85 #define ATAPI_TAPE_WRITE_CMD 0x0a
86 #define ATAPI_TAPE_WEOF 0x10
87 #define WEOF_WRITE_MASK 0x01
88 #define ATAPI_TAPE_SPACE_CMD 0x11
91 #define ATAPI_TAPE_ERASE 0x19
92 #define ATAPI_TAPE_MODE_SENSE 0x1a
93 #define ATAPI_TAPE_LOAD_UNLOAD 0x1b
94 #define LU_LOAD_MASK 0x01
95 #define LU_RETENSION_MASK 0x02
96 #define LU_EOT_MASK 0x04
98 #define DSC_POLL_INTERVAL 10
101 * MODE SENSE parameter header
104 u_char data_length; /* Total length of data */
105 u_char medium_type; /* Medium type (if any) */
106 u_char dsp; /* Device specific parameter */
107 u_char bdl; /* Block Descriptor Length */
111 * ATAPI tape drive Capabilities and Mechanical Status Page
113 #define ATAPI_TAPE_CAP_PAGE 0x2a
116 u_int page_code :6; /* Page code == 0x2a */
117 u_int reserved1_67 :2;
118 u_char page_length; /* Page Length == 0x12 */
121 u_int readonly :1; /* Read Only Mode */
122 u_int reserved4_1234 :4;
123 u_int reverse :1; /* Supports reverse direction */
124 u_int reserved4_67 :2;
125 u_int reserved5_012 :3;
126 u_int eformat :1; /* Supports ERASE formatting */
127 u_int reserved5_4 :1;
128 u_int qfa :1; /* Supports QFA formats */
129 u_int reserved5_67 :2;
130 u_int lock :1; /* Supports locking media */
131 u_int locked :1; /* The media is locked */
132 u_int prevent :1; /* Defaults to prevent state */
133 u_int eject :1; /* Supports eject */
134 u_int disconnect :1; /* Can break request > ctl */
135 u_int reserved6_5 :1;
136 u_int ecc :1; /* Supports error correction */
137 u_int compress :1; /* Supports data compression */
138 u_int reserved7_0 :1;
139 u_int blk512 :1; /* Supports 512b block size */
140 u_int blk1024 :1; /* Supports 1024b block size */
141 u_int reserved7_3456 :4;
142 u_int slowb :1; /* Restricts byte count */
143 u_short max_speed; /* Supported speed in KBps */
144 u_short max_defects; /* Max stored defect entries */
145 u_short ctl; /* Continuous Transfer Limit */
146 u_short speed; /* Current Speed, in KBps */
147 u_short buffer_size; /* Buffer Size, in 512 bytes */
153 * REQUEST SENSE structure
155 struct wst_reqsense {
156 u_int error_code :7; /* Current or deferred errors */
157 u_int valid :1; /* Follows QIC-157C */
158 u_char reserved1; /* Segment Number - Reserved */
159 u_int sense_key :4; /* Sense Key */
160 u_int reserved2_4 :1; /* Reserved */
161 u_int ili :1; /* Incorrect Length Indicator */
162 u_int eom :1; /* End Of Medium */
163 u_int filemark :1; /* Filemark */
164 u_int info __attribute__((packed)); /* Cmd specific info */
165 u_char asl; /* Additional sense length (n-7) */
166 u_int command_specific; /* Additional cmd specific info */
167 u_char asc; /* Additional Sense Code */
168 u_char ascq; /* Additional Sense Code Qualifier */
169 u_char replaceable_unit_code; /* Field Replaceable Unit Code */
170 u_int sk_specific1 :7; /* Sense Key Specific */
171 u_int sksv :1; /* Sense Key Specific info valid */
172 u_char sk_specific2; /* Sense Key Specific */
173 u_char sk_specific3; /* Sense Key Specific */
174 u_char pad[2]; /* Padding */
178 struct atapi *ata; /* Controller structure */
179 int unit; /* IDE bus drive unit */
180 int lun; /* Logical device unit */
181 int flags; /* Device state flags */
182 int blksize; /* Block size (512 | 1024) */
183 struct buf_queue_head buf_queue; /* Queue of i/o requests */
184 struct atapi_params *param; /* Drive parameters table */
185 struct wst_header header; /* MODE SENSE param header */
186 struct wst_cappage cap; /* Capabilities page info */
189 static struct wst *wsttab[NUNIT]; /* Drive info by unit number */
190 static int wstnlun = 0; /* Number of config'd drives */
192 int wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug);
193 static int wst_sense(struct wst *t);
194 static void wst_describe(struct wst *t);
195 static void wst_poll_dsc(struct wst *t);
196 static void wst_start(struct wst *t);
197 static void wst_done(struct wst *t, struct buf *bp, int resid, struct atapires result);
198 static int wst_error(struct wst *t, struct atapires result);
199 static void wst_drvinit(void *unused);
200 static int wst_space_cmd(struct wst *t, u_char function, u_int count);
201 static int wst_write_filemark(struct wst *t, u_char function);
202 static int wst_erase(struct wst *t);
203 static int wst_load_unload(struct wst *t, u_char finction);
204 static int wst_rewind(struct wst *t);
205 static void wst_reset(struct wst *t);
208 void wst_dump(int lun, char *label, void *data, int len);
211 wst_dump(int lun, char *label, void *data, int len)
215 printf("wst%d: %s %x", lun, label, *p++);
223 wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
228 if (wstnlun >= NUNIT) {
229 printf("wst: too many units\n");
232 if (!atapi_request_immediate) {
233 printf("wst: configuration error, ATAPI core code not present!\n");
235 "wst: check `options ATAPI_STATIC' in your kernel config file!\n");
238 t = malloc(sizeof(struct wst), M_TEMP, M_NOWAIT);
240 printf("wst: out of memory\n");
244 bzero(t, sizeof(struct wst));
245 bufq_init(&t->buf_queue);
249 lun = t->lun = wstnlun;
251 t->flags = WST_MEDIA_CHANGED | WST_DEBUG;
259 make_dev(&wst_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0640, "rwst%d", t->lun);
264 wst_sense(struct wst *t)
266 struct atapires result;
270 /* Get drive capabilities, some drives needs this repeated */
271 for (count = 0 ; count < 5 ; count++) {
272 result = atapi_request_immediate(t->ata, t->unit,
273 ATAPI_TAPE_MODE_SENSE,
274 8, /* DBD = 1 no block descr */
276 sizeof(buffer)>>8, sizeof(buffer),
278 0, 0, 0, 0, buffer, sizeof(buffer));
279 if (result.code == 0 || result.code == RES_UNDERRUN)
283 /* Some drives have shorter capabilities page. */
284 if (result.code == RES_UNDERRUN)
287 if (result.code == 0) {
288 bcopy(buffer, &t->header, sizeof(struct wst_header));
289 bcopy(buffer+sizeof(struct wst_header),
290 &t->cap, sizeof(struct wst_cappage));
291 if (t->cap.page_code != ATAPI_TAPE_CAP_PAGE)
293 t->cap.max_speed = ntohs(t->cap.max_speed);
294 t->cap.max_defects = ntohs(t->cap.max_defects);
295 t->cap.ctl = ntohs(t->cap.ctl);
296 t->cap.speed = ntohs(t->cap.speed);
297 t->cap.buffer_size = ntohs(t->cap.buffer_size);
298 t->blksize = (t->cap.blk512 ? 512 : (t->cap.blk1024 ? 1024 : 0));
305 wst_describe(struct wst *t)
307 printf("wst%d: ", t->lun);
308 switch (t->header.medium_type) {
309 case 0x00: printf("Drive empty"); break;
310 case 0x17: printf("Travan 1 (400 Mbyte) media"); break;
311 case 0xb6: printf("Travan 4 (4 Gbyte) media"); break;
312 default: printf("Unknown media (0x%x)", t->header.medium_type);
314 if (t->cap.readonly) printf(", readonly");
315 if (t->cap.reverse) printf(", reverse");
316 if (t->cap.eformat) printf(", eformat");
317 if (t->cap.qfa) printf(", qfa");
318 if (t->cap.lock) printf(", lock");
319 if (t->cap.locked) printf(", locked");
320 if (t->cap.prevent) printf(", prevent");
321 if (t->cap.eject) printf(", eject");
322 if (t->cap.disconnect) printf(", disconnect");
323 if (t->cap.ecc) printf(", ecc");
324 if (t->cap.compress) printf(", compress");
325 if (t->cap.blk512) printf(", 512b");
326 if (t->cap.blk1024) printf(", 1024b");
327 if (t->cap.slowb) printf(", slowb");
328 printf("\nwst%d: ", t->lun);
329 printf("Max speed=%dKb/s, ", t->cap.max_speed);
330 printf("Transfer limit=%d blocks, ", t->cap.ctl);
331 printf("Buffer size=%d blocks", t->cap.buffer_size);
336 wstopen(dev_t dev, int flags, int fmt, struct proc *p)
341 /* Check that the device number and that the ATAPI driver is loaded. */
342 if (lun >= wstnlun || !atapi_request_immediate) {
343 printf("ENXIO lun=%d, wstnlun=%d, im=%p\n",
344 lun, wstnlun, (void *)atapi_request_immediate);
348 if (t->flags == WST_OPEN)
351 printf("wst%d: Sense media type failed\n", t->lun);
352 t->flags &= ~WST_MEDIA_CHANGED;
353 t->flags &= ~(WST_DATA_WRITTEN | WST_FM_WRITTEN);
354 t->flags |= WST_OPEN;
359 wstclose(dev_t dev, int flags, int fmt, struct proc *p)
362 struct wst *t = wsttab[lun];
364 /* Flush buffers, some drives fail here, but they should report ctl = 0 */
365 if (t->cap.ctl && (t->flags & WST_DATA_WRITTEN))
366 wst_write_filemark(t, 0);
368 /* Write filemark if data written to tape */
369 if ((t->flags & (WST_DATA_WRITTEN | WST_FM_WRITTEN)) == WST_DATA_WRITTEN)
370 wst_write_filemark(t, WEOF_WRITE_MASK);
372 /* If minor is even rewind on close */
373 if (!(minor(dev) & 0x01))
376 t->flags &= ~WST_OPEN;
377 if (t->flags & WST_DEBUG)
378 printf("wst%d: %ud total bytes transferred\n", t->lun, wst_total);
379 t->flags &= ~WST_CTL_WARN;
384 wststrategy(struct buf *bp)
386 int lun = UNIT(bp->b_dev);
387 struct wst *t = wsttab[lun];
390 /* If it's a null transfer, return immediatly. */
391 if (bp->b_bcount == 0) {
397 /* Check for != blocksize requests */
398 if (bp->b_bcount % t->blksize) {
399 printf("wst%d: bad request, must be multiple of %d\n", lun, t->blksize);
401 bp->b_flags |= B_ERROR;
406 if (bp->b_bcount > t->blksize*t->cap.ctl) {
407 if ((t->flags & WST_CTL_WARN) == 0) {
408 printf("wst%d: WARNING: CTL exceeded %ld>%d\n",
409 lun, bp->b_bcount, t->blksize*t->cap.ctl);
410 t->flags |= WST_CTL_WARN;
415 wst_total += bp->b_bcount;
416 bufq_insert_tail(&t->buf_queue, bp);
422 wst_poll_dsc(struct wst *t)
424 /* We should use a final timeout here SOS XXX */
425 if (!(inb(t->ata->port + AR_STATUS) & ARS_DSC)) {
426 timeout((timeout_t*)wst_poll_dsc, t, DSC_POLL_INTERVAL);
429 t->ata->wait_for_dsc = 0;
434 wst_start(struct wst *t)
436 struct buf *bp = bufq_first(&t->buf_queue);
444 if (t->ata->wait_for_dsc)
445 printf("wst%d: ERROR! allready waiting for DSC\n", t->lun);
447 /* Sleep waiting for a ready drive (DSC) */
448 if (t->ata->use_dsc && !(inb(t->ata->port + AR_STATUS) & ARS_DSC)) {
449 t->ata->wait_for_dsc = 1;
450 timeout((timeout_t*)wst_poll_dsc, t, DSC_POLL_INTERVAL);
451 tsleep((caddr_t) t, 0, "wstdsc", 0);
454 bufq_remove(&t->buf_queue, bp);
455 blk_count = bp->b_bcount / t->blksize;
457 if (bp->b_flags & B_READ) {
458 op_code = ATAPI_TAPE_READ_CMD;
459 byte_count = bp->b_bcount;
461 op_code = ATAPI_TAPE_WRITE_CMD;
462 t->flags |= WST_DATA_WRITTEN;
463 byte_count = -bp->b_bcount;
466 atapi_request_callback(t->ata, t->unit, op_code, 1,
467 blk_count>>16, blk_count>>8, blk_count,
468 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
469 (u_char*) bp->b_data, byte_count,
470 (void*)wst_done, t, bp);
474 wst_done(struct wst *t, struct buf *bp, int resid,
475 struct atapires result)
478 printf("wst_done: ");
479 wst_error(t, result);
481 bp->b_flags |= B_ERROR;
491 wst_error(struct wst *t, struct atapires result)
493 struct wst_reqsense sense;
495 if (result.code != RES_ERR) {
496 printf("wst%d: ERROR code=%d, status=%b, error=%b\n", t->lun,
497 result.code, result.status, ARS_BITS, result.error, AER_BITS);
501 if ((result.error & AER_SKEY) && (result.status & ARS_CHECK)) {
502 atapi_request_immediate(t->ata, t->unit,
503 ATAPI_TAPE_REQUEST_SENSE,
504 0, 0, 0, sizeof(sense),
506 0, 0, 0, 0, (char*) &sense, sizeof(struct wst_reqsense));
507 /*wst_dump(t->lun, "req_sense", &sense, sizeof(struct wst_reqsense));*/
509 switch (result.error & AER_SKEY) {
510 case AER_SK_NOT_READY:
511 if (result.error & ~AER_SKEY) {
512 if (t->flags & WST_DEBUG)
513 printf("wst%d: not ready\n", t->lun);
516 if (!(t->flags & WST_MEDIA_CHANGED))
517 if (t->flags & WST_DEBUG)
518 printf("wst%d: no media\n", t->lun);
519 t->flags |= WST_MEDIA_CHANGED;
522 case AER_SK_BLANK_CHECK:
523 if (t->flags & WST_DEBUG)
524 printf("wst%d: EOD encountered\n", t->lun);
527 case AER_SK_MEDIUM_ERROR:
528 if (t->flags & WST_DEBUG)
529 printf("wst%d: nonrecovered data error\n", t->lun);
532 case AER_SK_HARDWARE_ERROR:
533 if (t->flags & WST_DEBUG)
534 printf("wst%d: nonrecovered hardware error\n", t->lun);
537 case AER_SK_ILLEGAL_REQUEST:
538 if (t->flags & WST_DEBUG)
539 printf("wst%d: invalid command\n", t->lun);
542 case AER_SK_UNIT_ATTENTION:
543 if (!(t->flags & WST_MEDIA_CHANGED))
544 printf("wst%d: media changed\n", t->lun);
545 t->flags |= WST_MEDIA_CHANGED;
548 case AER_SK_DATA_PROTECT:
549 if (t->flags & WST_DEBUG)
550 printf("wst%d: reading read protected data\n", t->lun);
553 case AER_SK_ABORTED_COMMAND:
554 if (t->flags & WST_DEBUG)
555 printf("wst%d: command aborted\n", t->lun);
558 case AER_SK_MISCOMPARE:
559 if (t->flags & WST_DEBUG)
560 printf("wst%d: data don't match medium\n", t->lun);
564 printf("wst%d: i/o error, status=%b, error=%b\n", t->lun,
565 result.status, ARS_BITS, result.error, AER_BITS);
567 printf("total=%u ERR=%x len=%ld ASC=%x ASCQ=%x\n",
568 wst_total, sense.error_code, (long)ntohl(sense.info),
569 sense.asc, sense.ascq);
574 wstioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
578 struct wst *t = wsttab[lun];
583 struct mtget *g = (struct mtget *) addr;
585 bzero(g, sizeof(struct mtget));
588 g->mt_blksiz = t->blksize;
589 g->mt_comp = t->cap.compress;
590 g->mt_density0 = 0; g->mt_density1 = 0;
591 g->mt_density2 = 0; g->mt_density3 = 0;
592 g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
593 g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
594 g->mt_comp0 = 0; g->mt_comp1 = 0;
595 g->mt_comp2 = 0; g->mt_comp3 = 0;
601 struct mtop *mt = (struct mtop *)addr;
603 switch ((short) (mt->mt_op)) {
605 for (i=0; i < mt->mt_count && !error; i++)
606 error = wst_write_filemark(t, WEOF_WRITE_MASK);
610 error = wst_space_cmd(t, SP_FM, mt->mt_count);
614 error = wst_space_cmd(t, SP_FM, -(mt->mt_count));
617 error = EINVAL; break;
619 error = EINVAL; break;
621 error = wst_rewind(t);
624 #if 1 /* Misuse as a reset func for now */
629 if (error = wst_rewind(t))
631 error = wst_load_unload(t, !LU_LOAD_MASK);
635 error = wst_write_filemark(t, 0);
638 error = EINVAL; break;
640 error = EINVAL; break;
642 error = EINVAL; break;
644 error = EINVAL; break;
646 error = wst_erase(t);
649 error = wst_space_cmd(t, SP_EOD, 0);
652 error = EINVAL; break;
654 error = wst_load_unload(t, LU_RETENSION_MASK|LU_LOAD_MASK);
668 wst_space_cmd(struct wst *t, u_char function, u_int count)
670 struct atapires result;
672 result = atapi_request_wait(t->ata, t->unit,
673 ATAPI_TAPE_SPACE_CMD, function,
674 count>>16, count>>8, count,
675 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
677 printf("wst_space_cmd: ");
678 wst_error(t, result);
685 wst_write_filemark(struct wst *t, u_char function)
687 struct atapires result;
690 if (t->flags & WST_FM_WRITTEN)
691 t->flags &= ~WST_DATA_WRITTEN;
693 t->flags |= WST_FM_WRITTEN;
695 result = atapi_request_wait(t->ata, t->unit,
696 ATAPI_TAPE_WEOF, 0, 0, 0, function,
697 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
699 printf("wst_write_filemark: ");
700 wst_error(t, result);
707 wst_load_unload(struct wst *t, u_char function)
709 struct atapires result;
711 result = atapi_request_wait(t->ata, t->unit,
712 ATAPI_TAPE_LOAD_UNLOAD, 0, 0, 0, function,
713 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
715 printf("wst_load_unload: ");
716 wst_error(t, result);
723 wst_erase(struct wst *t)
726 struct atapires result;
728 error = wst_rewind(t);
731 result = atapi_request_wait(t->ata, t->unit,
732 ATAPI_TAPE_ERASE, 3, 0, 0, 0,
733 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
736 printf("wst_erase: ");
737 wst_error(t, result);
744 wst_rewind(struct wst *t)
746 struct atapires result;
748 result = atapi_request_wait(t->ata, t->unit,
749 ATAPI_TAPE_REWIND, 0, 0, 0, 0,
750 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
753 printf("wst_rewind: ");
754 wst_error(t, result);
761 wst_reset(struct wst *t)
763 outb(t->ata->port + AR_DRIVE, ARD_DRIVE1);
765 outb(t->ata->port + AR_COMMAND, 0x08);
770 wst_drvinit(void *unused)
772 cdevsw_add(&wst_cdevsw);
775 SYSINIT(wstdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wst_drvinit,NULL)