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