FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/wst.c
1 /*-
2 * Copyright (c) 1998 Søren Schmidt
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 * $FreeBSD$
29 */
30
31 #include "wdc.h"
32 #include "opt_ddb.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/conf.h>
38 #include <sys/malloc.h>
39 #include <sys/buf.h>
40 #include <sys/mtio.h>
41 #include <machine/clock.h>
42 #include <i386/isa/atapi.h>
43
44 static d_open_t wstopen;
45 static d_close_t wstclose;
46 static d_ioctl_t wstioctl;
47 static d_strategy_t wststrategy;
48
49 #define CDEV_MAJOR 90
50
51 static struct cdevsw wst_cdevsw = {
52 /* open */ wstopen,
53 /* close */ wstclose,
54 /* read */ physread,
55 /* write */ physwrite,
56 /* ioctl */ wstioctl,
57 /* poll */ nopoll,
58 /* mmap */ nommap,
59 /* strategy */ wststrategy,
60 /* name */ "wst",
61 /* maj */ CDEV_MAJOR,
62 /* dump */ nodump,
63 /* psize */ nopsize,
64 /* flags */ 0,
65 /* bmaj */ -1
66 };
67
68 static unsigned int wst_total = 0;
69
70 #define NUNIT (NWDC*2)
71 #define UNIT(d) ((minor(d) >> 3) & 3)
72
73 #define WST_OPEN 0x0001 /* The device is opened */
74 #define WST_MEDIA_CHANGED 0x0002 /* The media have changed */
75 #define WST_DATA_WRITTEN 0x0004 /* Data has been written */
76 #define WST_FM_WRITTEN 0x0008 /* Filemark has been written */
77 #define WST_DEBUG 0x0010 /* Print debug info */
78 #define WST_CTL_WARN 0x0020 /* Have we warned about CTL wrong? */
79
80 /* ATAPI tape commands not in std ATAPI command set */
81 #define ATAPI_TAPE_REWIND 0x01
82 #define ATAPI_TAPE_REQUEST_SENSE 0x03
83 #define ATAPI_TAPE_READ_CMD 0x08
84 #define ATAPI_TAPE_WRITE_CMD 0x0a
85 #define ATAPI_TAPE_WEOF 0x10
86 #define WEOF_WRITE_MASK 0x01
87 #define ATAPI_TAPE_SPACE_CMD 0x11
88 #define SP_FM 0x01
89 #define SP_EOD 0x03
90 #define ATAPI_TAPE_ERASE 0x19
91 #define ATAPI_TAPE_MODE_SENSE 0x1a
92 #define ATAPI_TAPE_LOAD_UNLOAD 0x1b
93 #define LU_LOAD_MASK 0x01
94 #define LU_RETENSION_MASK 0x02
95 #define LU_EOT_MASK 0x04
96
97 #define DSC_POLL_INTERVAL 10
98
99 /*
100 * MODE SENSE parameter header
101 */
102 struct wst_header {
103 u_char data_length; /* Total length of data */
104 u_char medium_type; /* Medium type (if any) */
105 u_char dsp; /* Device specific parameter */
106 u_char bdl; /* Block Descriptor Length */
107 };
108
109 /*
110 * ATAPI tape drive Capabilities and Mechanical Status Page
111 */
112 #define ATAPI_TAPE_CAP_PAGE 0x2a
113
114 struct wst_cappage {
115 u_int page_code :6; /* Page code == 0x2a */
116 u_int reserved1_67 :2;
117 u_char page_length; /* Page Length == 0x12 */
118 u_char reserved2;
119 u_char reserved3;
120 u_int readonly :1; /* Read Only Mode */
121 u_int reserved4_1234 :4;
122 u_int reverse :1; /* Supports reverse direction */
123 u_int reserved4_67 :2;
124 u_int reserved5_012 :3;
125 u_int eformat :1; /* Supports ERASE formatting */
126 u_int reserved5_4 :1;
127 u_int qfa :1; /* Supports QFA formats */
128 u_int reserved5_67 :2;
129 u_int lock :1; /* Supports locking media */
130 u_int locked :1; /* The media is locked */
131 u_int prevent :1; /* Defaults to prevent state */
132 u_int eject :1; /* Supports eject */
133 u_int disconnect :1; /* Can break request > ctl */
134 u_int reserved6_5 :1;
135 u_int ecc :1; /* Supports error correction */
136 u_int compress :1; /* Supports data compression */
137 u_int reserved7_0 :1;
138 u_int blk512 :1; /* Supports 512b block size */
139 u_int blk1024 :1; /* Supports 1024b block size */
140 u_int reserved7_3456 :4;
141 u_int slowb :1; /* Restricts byte count */
142 u_short max_speed; /* Supported speed in KBps */
143 u_short max_defects; /* Max stored defect entries */
144 u_short ctl; /* Continuous Transfer Limit */
145 u_short speed; /* Current Speed, in KBps */
146 u_short buffer_size; /* Buffer Size, in 512 bytes */
147 u_char reserved18;
148 u_char reserved19;
149 };
150
151 /*
152 * REQUEST SENSE structure
153 */
154 struct wst_reqsense {
155 u_int error_code :7; /* Current or deferred errors */
156 u_int valid :1; /* Follows QIC-157C */
157 u_char reserved1; /* Segment Number - Reserved */
158 u_int sense_key :4; /* Sense Key */
159 u_int reserved2_4 :1; /* Reserved */
160 u_int ili :1; /* Incorrect Length Indicator */
161 u_int eom :1; /* End Of Medium */
162 u_int filemark :1; /* Filemark */
163 u_int info __attribute__((packed)); /* Cmd specific info */
164 u_char asl; /* Additional sense length (n-7) */
165 u_int command_specific; /* Additional cmd specific info */
166 u_char asc; /* Additional Sense Code */
167 u_char ascq; /* Additional Sense Code Qualifier */
168 u_char replaceable_unit_code; /* Field Replaceable Unit Code */
169 u_int sk_specific1 :7; /* Sense Key Specific */
170 u_int sksv :1; /* Sense Key Specific info valid */
171 u_char sk_specific2; /* Sense Key Specific */
172 u_char sk_specific3; /* Sense Key Specific */
173 u_char pad[2]; /* Padding */
174 };
175
176 struct wst {
177 struct atapi *ata; /* Controller structure */
178 int unit; /* IDE bus drive unit */
179 int lun; /* Logical device unit */
180 int flags; /* Device state flags */
181 int blksize; /* Block size (512 | 1024) */
182 struct buf_queue_head buf_queue; /* Queue of i/o requests */
183 struct atapi_params *param; /* Drive parameters table */
184 struct wst_header header; /* MODE SENSE param header */
185 struct wst_cappage cap; /* Capabilities page info */
186 };
187
188 static struct wst *wsttab[NUNIT]; /* Drive info by unit number */
189 static int wstnlun = 0; /* Number of config'd drives */
190
191 int wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug);
192 static int wst_sense(struct wst *t);
193 static void wst_describe(struct wst *t);
194 static void wst_poll_dsc(struct wst *t);
195 static void wst_start(struct wst *t);
196 static void wst_done(struct wst *t, struct buf *bp, int resid, struct atapires result);
197 static int wst_error(struct wst *t, struct atapires result);
198 static void wst_drvinit(void *unused);
199 static int wst_space_cmd(struct wst *t, u_char function, u_int count);
200 static int wst_write_filemark(struct wst *t, u_char function);
201 static int wst_erase(struct wst *t);
202 static int wst_load_unload(struct wst *t, u_char finction);
203 static int wst_rewind(struct wst *t);
204 static void wst_reset(struct wst *t);
205
206 #ifdef DDB
207 void wst_dump(int lun, char *label, void *data, int len);
208
209 void
210 wst_dump(int lun, char *label, void *data, int len)
211 {
212 u_char *p = data;
213
214 printf("wst%d: %s %x", lun, label, *p++);
215 while(--len > 0)
216 printf("-%x", *p++);
217 printf("\n");
218 }
219 #endif
220
221 int
222 wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
223 {
224 struct wst *t;
225 int lun;
226
227 if (wstnlun >= NUNIT) {
228 printf("wst: too many units\n");
229 return(-1);
230 }
231 if (!atapi_request_immediate) {
232 printf("wst: configuration error, ATAPI core code not present!\n");
233 printf(
234 "wst: check `options ATAPI_STATIC' in your kernel config file!\n");
235 return(-1);
236 }
237 t = malloc(sizeof(struct wst), M_TEMP, M_NOWAIT);
238 if (!t) {
239 printf("wst: out of memory\n");
240 return(-1);
241 }
242 wsttab[wstnlun] = t;
243 bzero(t, sizeof(struct wst));
244 bufq_init(&t->buf_queue);
245 t->ata = ata;
246 t->unit = unit;
247 t->ata->use_dsc = 1;
248 lun = t->lun = wstnlun;
249 t->param = ap;
250 t->flags = WST_MEDIA_CHANGED | WST_DEBUG;
251
252 if (wst_sense(t))
253 return -1;
254
255 wst_describe(t);
256 wstnlun++;
257
258 make_dev(&wst_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0640, "rwst%d", t->lun);
259 return(1);
260 }
261
262 static int
263 wst_sense(struct wst *t)
264 {
265 struct atapires result;
266 int count;
267 char buffer[255];
268
269 /* Get drive capabilities, some drives needs this repeated */
270 for (count = 0 ; count < 5 ; count++) {
271 result = atapi_request_immediate(t->ata, t->unit,
272 ATAPI_TAPE_MODE_SENSE,
273 8, /* DBD = 1 no block descr */
274 ATAPI_TAPE_CAP_PAGE,
275 sizeof(buffer)>>8, sizeof(buffer),
276 0, 0, 0, 0, 0, 0, 0,
277 0, 0, 0, 0, buffer, sizeof(buffer));
278 if (result.code == 0 || result.code == RES_UNDERRUN)
279 break;
280 }
281
282 /* Some drives have shorter capabilities page. */
283 if (result.code == RES_UNDERRUN)
284 result.code = 0;
285
286 if (result.code == 0) {
287 bcopy(buffer, &t->header, sizeof(struct wst_header));
288 bcopy(buffer+sizeof(struct wst_header),
289 &t->cap, sizeof(struct wst_cappage));
290 if (t->cap.page_code != ATAPI_TAPE_CAP_PAGE)
291 return 1;
292 t->cap.max_speed = ntohs(t->cap.max_speed);
293 t->cap.max_defects = ntohs(t->cap.max_defects);
294 t->cap.ctl = ntohs(t->cap.ctl);
295 t->cap.speed = ntohs(t->cap.speed);
296 t->cap.buffer_size = ntohs(t->cap.buffer_size);
297 t->blksize = (t->cap.blk512 ? 512 : (t->cap.blk1024 ? 1024 : 0));
298 return 0;
299 }
300 return 1;
301 }
302
303 static void
304 wst_describe(struct wst *t)
305 {
306 printf("wst%d: ", t->lun);
307 switch (t->header.medium_type) {
308 case 0x00: printf("Drive empty"); break;
309 case 0x17: printf("Travan 1 (400 Mbyte) media"); break;
310 case 0xb6: printf("Travan 4 (4 Gbyte) media"); break;
311 default: printf("Unknown media (0x%x)", t->header.medium_type);
312 }
313 if (t->cap.readonly) printf(", readonly");
314 if (t->cap.reverse) printf(", reverse");
315 if (t->cap.eformat) printf(", eformat");
316 if (t->cap.qfa) printf(", qfa");
317 if (t->cap.lock) printf(", lock");
318 if (t->cap.locked) printf(", locked");
319 if (t->cap.prevent) printf(", prevent");
320 if (t->cap.eject) printf(", eject");
321 if (t->cap.disconnect) printf(", disconnect");
322 if (t->cap.ecc) printf(", ecc");
323 if (t->cap.compress) printf(", compress");
324 if (t->cap.blk512) printf(", 512b");
325 if (t->cap.blk1024) printf(", 1024b");
326 if (t->cap.slowb) printf(", slowb");
327 printf("\nwst%d: ", t->lun);
328 printf("Max speed=%dKb/s, ", t->cap.max_speed);
329 printf("Transfer limit=%d blocks, ", t->cap.ctl);
330 printf("Buffer size=%d blocks", t->cap.buffer_size);
331 printf("\n");
332 }
333
334 int
335 wstopen(dev_t dev, int flags, int fmt, struct proc *p)
336 {
337 int lun = UNIT(dev);
338 struct wst *t;
339
340 /* Check that the device number and that the ATAPI driver is loaded. */
341 if (lun >= wstnlun || !atapi_request_immediate) {
342 printf("ENXIO lun=%d, wstnlun=%d, im=%p\n",
343 lun, wstnlun, (void *)atapi_request_immediate);
344 return(ENXIO);
345 }
346 t = wsttab[lun];
347 if (t->flags == WST_OPEN)
348 return EBUSY;
349 if (wst_sense(t))
350 printf("wst%d: Sense media type failed\n", t->lun);
351 t->flags &= ~WST_MEDIA_CHANGED;
352 t->flags &= ~(WST_DATA_WRITTEN | WST_FM_WRITTEN);
353 t->flags |= WST_OPEN;
354 return(0);
355 }
356
357 int
358 wstclose(dev_t dev, int flags, int fmt, struct proc *p)
359 {
360 int lun = UNIT(dev);
361 struct wst *t = wsttab[lun];
362
363 /* Flush buffers, some drives fail here, but they should report ctl = 0 */
364 if (t->cap.ctl && (t->flags & WST_DATA_WRITTEN))
365 wst_write_filemark(t, 0);
366
367 /* Write filemark if data written to tape */
368 if ((t->flags & (WST_DATA_WRITTEN | WST_FM_WRITTEN)) == WST_DATA_WRITTEN)
369 wst_write_filemark(t, WEOF_WRITE_MASK);
370
371 /* If minor is even rewind on close */
372 if (!(minor(dev) & 0x01))
373 wst_rewind(t);
374
375 t->flags &= ~WST_OPEN;
376 if (t->flags & WST_DEBUG)
377 printf("wst%d: %ud total bytes transferred\n", t->lun, wst_total);
378 t->flags &= ~WST_CTL_WARN;
379 return(0);
380 }
381
382 void
383 wststrategy(struct buf *bp)
384 {
385 int lun = UNIT(bp->b_dev);
386 struct wst *t = wsttab[lun];
387 int x;
388
389 /* If it's a null transfer, return immediatly. */
390 if (bp->b_bcount == 0) {
391 bp->b_resid = 0;
392 biodone(bp);
393 return;
394 }
395
396 /* Check for != blocksize requests */
397 if (bp->b_bcount % t->blksize) {
398 printf("wst%d: bad request, must be multiple of %d\n", lun, t->blksize);
399 bp->b_error = EIO;
400 bp->b_flags |= B_ERROR;
401 biodone(bp);
402 return;
403 }
404
405 if (bp->b_bcount > t->blksize*t->cap.ctl) {
406 if ((t->flags & WST_CTL_WARN) == 0) {
407 printf("wst%d: WARNING: CTL exceeded %ld>%d\n",
408 lun, bp->b_bcount, t->blksize*t->cap.ctl);
409 t->flags |= WST_CTL_WARN;
410 }
411 }
412
413 x = splbio();
414 wst_total += bp->b_bcount;
415 bufq_insert_tail(&t->buf_queue, bp);
416 wst_start(t);
417 splx(x);
418 }
419
420 static void
421 wst_poll_dsc(struct wst *t)
422 {
423 /* We should use a final timeout here SOS XXX */
424 if (!(inb(t->ata->port + AR_STATUS) & ARS_DSC)) {
425 timeout((timeout_t*)wst_poll_dsc, t, DSC_POLL_INTERVAL);
426 return;
427 }
428 t->ata->wait_for_dsc = 0;
429 wakeup((caddr_t)t);
430 }
431
432 static void
433 wst_start(struct wst *t)
434 {
435 struct buf *bp = bufq_first(&t->buf_queue);
436 u_long blk_count;
437 u_char op_code;
438 long byte_count;
439
440 if (!bp)
441 return;
442
443 if (t->ata->wait_for_dsc)
444 printf("wst%d: ERROR! allready waiting for DSC\n", t->lun);
445
446 /* Sleep waiting for a ready drive (DSC) */
447 if (t->ata->use_dsc && !(inb(t->ata->port + AR_STATUS) & ARS_DSC)) {
448 t->ata->wait_for_dsc = 1;
449 timeout((timeout_t*)wst_poll_dsc, t, DSC_POLL_INTERVAL);
450 tsleep((caddr_t) t, 0, "wstdsc", 0);
451 }
452
453 bufq_remove(&t->buf_queue, bp);
454 blk_count = bp->b_bcount / t->blksize;
455
456 if (bp->b_flags & B_READ) {
457 op_code = ATAPI_TAPE_READ_CMD;
458 byte_count = bp->b_bcount;
459 } else {
460 op_code = ATAPI_TAPE_WRITE_CMD;
461 t->flags |= WST_DATA_WRITTEN;
462 byte_count = -bp->b_bcount;
463 }
464
465 atapi_request_callback(t->ata, t->unit, op_code, 1,
466 blk_count>>16, blk_count>>8, blk_count,
467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
468 (u_char*) bp->b_data, byte_count,
469 (void*)wst_done, t, bp);
470 }
471
472 static void
473 wst_done(struct wst *t, struct buf *bp, int resid,
474 struct atapires result)
475 {
476 if (result.code) {
477 printf("wst_done: ");
478 wst_error(t, result);
479 bp->b_error = EIO;
480 bp->b_flags |= B_ERROR;
481 }
482 else
483 bp->b_resid = resid;
484
485 biodone(bp);
486 /*wst_start(t);*/
487 }
488
489 static int
490 wst_error(struct wst *t, struct atapires result)
491 {
492 struct wst_reqsense sense;
493
494 if (result.code != RES_ERR) {
495 printf("wst%d: ERROR code=%d, status=%b, error=%b\n", t->lun,
496 result.code, result.status, ARS_BITS, result.error, AER_BITS);
497 return 1;
498 }
499
500 if ((result.error & AER_SKEY) && (result.status & ARS_CHECK)) {
501 atapi_request_immediate(t->ata, t->unit,
502 ATAPI_TAPE_REQUEST_SENSE,
503 0, 0, 0, sizeof(sense),
504 0, 0, 0, 0, 0, 0, 0,
505 0, 0, 0, 0, (char*) &sense, sizeof(struct wst_reqsense));
506 /*wst_dump(t->lun, "req_sense", &sense, sizeof(struct wst_reqsense));*/
507 }
508 switch (result.error & AER_SKEY) {
509 case AER_SK_NOT_READY:
510 if (result.error & ~AER_SKEY) {
511 if (t->flags & WST_DEBUG)
512 printf("wst%d: not ready\n", t->lun);
513 break;
514 }
515 if (!(t->flags & WST_MEDIA_CHANGED))
516 if (t->flags & WST_DEBUG)
517 printf("wst%d: no media\n", t->lun);
518 t->flags |= WST_MEDIA_CHANGED;
519 break;
520
521 case AER_SK_BLANK_CHECK:
522 if (t->flags & WST_DEBUG)
523 printf("wst%d: EOD encountered\n", t->lun);
524 break;
525
526 case AER_SK_MEDIUM_ERROR:
527 if (t->flags & WST_DEBUG)
528 printf("wst%d: nonrecovered data error\n", t->lun);
529 break;
530
531 case AER_SK_HARDWARE_ERROR:
532 if (t->flags & WST_DEBUG)
533 printf("wst%d: nonrecovered hardware error\n", t->lun);
534 break;
535
536 case AER_SK_ILLEGAL_REQUEST:
537 if (t->flags & WST_DEBUG)
538 printf("wst%d: invalid command\n", t->lun);
539 break;
540
541 case AER_SK_UNIT_ATTENTION:
542 if (!(t->flags & WST_MEDIA_CHANGED))
543 printf("wst%d: media changed\n", t->lun);
544 t->flags |= WST_MEDIA_CHANGED;
545 break;
546
547 case AER_SK_DATA_PROTECT:
548 if (t->flags & WST_DEBUG)
549 printf("wst%d: reading read protected data\n", t->lun);
550 break;
551
552 case AER_SK_ABORTED_COMMAND:
553 if (t->flags & WST_DEBUG)
554 printf("wst%d: command aborted\n", t->lun);
555 break;
556
557 case AER_SK_MISCOMPARE:
558 if (t->flags & WST_DEBUG)
559 printf("wst%d: data don't match medium\n", t->lun);
560 break;
561
562 default:
563 printf("wst%d: i/o error, status=%b, error=%b\n", t->lun,
564 result.status, ARS_BITS, result.error, AER_BITS);
565 }
566 printf("total=%u ERR=%x len=%ld ASC=%x ASCQ=%x\n",
567 wst_total, sense.error_code, (long)ntohl(sense.info),
568 sense.asc, sense.ascq);
569 return 1;
570 }
571
572 int
573 wstioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
574 {
575 int lun = UNIT(dev);
576 int error = 0;
577 struct wst *t = wsttab[lun];
578
579 switch (cmd) {
580 case MTIOCGET:
581 {
582 struct mtget *g = (struct mtget *) addr;
583
584 bzero(g, sizeof(struct mtget));
585 g->mt_type = 7;
586 g->mt_density = 1;
587 g->mt_blksiz = t->blksize;
588 g->mt_comp = t->cap.compress;
589 g->mt_density0 = 0; g->mt_density1 = 0;
590 g->mt_density2 = 0; g->mt_density3 = 0;
591 g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
592 g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
593 g->mt_comp0 = 0; g->mt_comp1 = 0;
594 g->mt_comp2 = 0; g->mt_comp3 = 0;
595 break;
596 }
597 case MTIOCTOP:
598 {
599 int i;
600 struct mtop *mt = (struct mtop *)addr;
601
602 switch ((short) (mt->mt_op)) {
603 case MTWEOF:
604 for (i=0; i < mt->mt_count && !error; i++)
605 error = wst_write_filemark(t, WEOF_WRITE_MASK);
606 break;
607 case MTFSF:
608 if (mt->mt_count)
609 error = wst_space_cmd(t, SP_FM, mt->mt_count);
610 break;
611 case MTBSF:
612 if (mt->mt_count)
613 error = wst_space_cmd(t, SP_FM, -(mt->mt_count));
614 break;
615 case MTFSR:
616 error = EINVAL; break;
617 case MTBSR:
618 error = EINVAL; break;
619 case MTREW:
620 error = wst_rewind(t);
621 break;
622 case MTOFFL:
623 #if 1 /* Misuse as a reset func for now */
624 wst_reset(t);
625 wst_sense(t);
626 wst_describe(t);
627 #else
628 if (error = wst_rewind(t))
629 break;
630 error = wst_load_unload(t, !LU_LOAD_MASK);
631 #endif
632 break;
633 case MTNOP:
634 error = wst_write_filemark(t, 0);
635 break;
636 case MTCACHE:
637 error = EINVAL; break;
638 case MTNOCACHE:
639 error = EINVAL; break;
640 case MTSETBSIZ:
641 error = EINVAL; break;
642 case MTSETDNSTY:
643 error = EINVAL; break;
644 case MTERASE:
645 error = wst_erase(t);
646 break;
647 case MTEOD:
648 error = wst_space_cmd(t, SP_EOD, 0);
649 break;
650 case MTCOMP:
651 error = EINVAL; break;
652 case MTRETENS:
653 error = wst_load_unload(t, LU_RETENSION_MASK|LU_LOAD_MASK);
654 break;
655 default:
656 error = EINVAL;
657 }
658 return error;
659 }
660 default:
661 return(ENOTTY);
662 }
663 return(error);
664 }
665
666 static int
667 wst_space_cmd(struct wst *t, u_char function, u_int count)
668 {
669 struct atapires result;
670
671 result = atapi_request_wait(t->ata, t->unit,
672 ATAPI_TAPE_SPACE_CMD, function,
673 count>>16, count>>8, count,
674 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
675 if (result.code) {
676 printf("wst_space_cmd: ");
677 wst_error(t, result);
678 return EIO;
679 }
680 return 0;
681 }
682
683 static int
684 wst_write_filemark(struct wst *t, u_char function)
685 {
686 struct atapires result;
687
688 if (function) {
689 if (t->flags & WST_FM_WRITTEN)
690 t->flags &= ~WST_DATA_WRITTEN;
691 else
692 t->flags |= WST_FM_WRITTEN;
693 }
694 result = atapi_request_wait(t->ata, t->unit,
695 ATAPI_TAPE_WEOF, 0, 0, 0, function,
696 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
697 if (result.code) {
698 printf("wst_write_filemark: ");
699 wst_error(t, result);
700 return EIO;
701 }
702 return 0;
703 }
704
705 static int
706 wst_load_unload(struct wst *t, u_char function)
707 {
708 struct atapires result;
709
710 result = atapi_request_wait(t->ata, t->unit,
711 ATAPI_TAPE_LOAD_UNLOAD, 0, 0, 0, function,
712 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0);
713 if (result.code) {
714 printf("wst_load_unload: ");
715 wst_error(t, result);
716 return EIO;
717 }
718 return 0;
719 }
720
721 static int
722 wst_erase(struct wst *t)
723 {
724 int error;
725 struct atapires result;
726
727 error = wst_rewind(t);
728 if (error)
729 return error;
730 result = atapi_request_wait(t->ata, t->unit,
731 ATAPI_TAPE_ERASE, 3, 0, 0, 0,
732 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
733 NULL, 0);
734 if (result.code) {
735 printf("wst_erase: ");
736 wst_error(t, result);
737 return EIO;
738 }
739 return 0;
740 }
741
742 static int
743 wst_rewind(struct wst *t)
744 {
745 struct atapires result;
746
747 result = atapi_request_wait(t->ata, t->unit,
748 ATAPI_TAPE_REWIND, 0, 0, 0, 0,
749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
750 NULL, 0);
751 if (result.code) {
752 printf("wst_rewind: ");
753 wst_error(t, result);
754 return EIO;
755 }
756 return 0;
757 }
758
759 static void
760 wst_reset(struct wst *t)
761 {
762 outb(t->ata->port + AR_DRIVE, ARD_DRIVE1);
763 DELAY(30);
764 outb(t->ata->port + AR_COMMAND, 0x08);
765 DELAY(30);
766 }
767
768 static void
769 wst_drvinit(void *unused)
770 {
771 cdevsw_add(&wst_cdevsw);
772 }
773
774 SYSINIT(wstdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wst_drvinit,NULL)
Cache object: c6d68897a922911347083e027740774e
|