Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / dev / disk / wst / 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: 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 $
30  */
31
32 #include "wdc.h"
33 #include "opt_ddb.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/conf.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/mtio.h>
42 #include <machine/clock.h>
43 #include <i386/isa/atapi.h>
44
45 static  d_open_t    wstopen;
46 static  d_close_t   wstclose;
47 static  d_ioctl_t   wstioctl;
48 static  d_strategy_t    wststrategy;
49
50 #define CDEV_MAJOR 90
51
52 static struct cdevsw wst_cdevsw = {
53         /* open */      wstopen,
54         /* close */     wstclose,
55         /* read */      physread,
56         /* write */     physwrite,
57         /* ioctl */     wstioctl,
58         /* poll */      nopoll,
59         /* mmap */      nommap,
60         /* strategy */  wststrategy,
61         /* name */      "wst",
62         /* maj */       CDEV_MAJOR,
63         /* dump */      nodump,
64         /* psize */     nopsize,
65         /* flags */     0,
66         /* bmaj */      -1
67 };
68
69 static unsigned int wst_total = 0;
70
71 #define NUNIT                   (NWDC*2)
72 #define UNIT(d)                 ((minor(d) >> 3) & 3)
73
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? */
80
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
89 #define     SP_FM                               0x01
90 #define     SP_EOD                              0x03
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
97
98 #define DSC_POLL_INTERVAL       10
99
100 /* 
101  * MODE SENSE parameter header
102  */
103 struct wst_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 */
108 };
109
110 /*
111  * ATAPI tape drive Capabilities and Mechanical Status Page
112  */
113 #define ATAPI_TAPE_CAP_PAGE     0x2a
114
115 struct wst_cappage {
116     u_int   page_code           :6;     /* Page code == 0x2a */
117     u_int   reserved1_67        :2;
118     u_char  page_length;                /* Page Length == 0x12 */
119     u_char  reserved2;
120     u_char  reserved3;
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 */
148     u_char  reserved18;
149     u_char  reserved19;
150 };
151
152 /*
153  * REQUEST SENSE structure
154  */
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 */
175 };
176
177 struct wst {
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 */
187 };
188
189 static struct wst *wsttab[NUNIT];       /* Drive info by unit number */
190 static int wstnlun = 0;                 /* Number of config'd drives */
191
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);
206
207 #ifdef DDB
208 void  wst_dump(int lun, char *label, void *data, int len);
209
210 void 
211 wst_dump(int lun, char *label, void *data, int len)
212 {
213     u_char *p = data;
214
215     printf("wst%d: %s %x", lun, label, *p++);
216     while(--len > 0)
217         printf("-%x", *p++);
218     printf("\n");
219 }
220 #endif
221
222 int 
223 wstattach(struct atapi *ata, int unit, struct atapi_params *ap, int debug)
224 {
225     struct wst *t;
226     int lun;
227
228     if (wstnlun >= NUNIT) {
229         printf("wst: too many units\n");
230         return(-1);
231     }
232     if (!atapi_request_immediate) {
233         printf("wst: configuration error, ATAPI core code not present!\n");
234         printf(
235             "wst: check `options ATAPI_STATIC' in your kernel config file!\n");
236         return(-1);
237     }
238     t = malloc(sizeof(struct wst), M_TEMP, M_NOWAIT);
239     if (!t) {
240         printf("wst: out of memory\n");
241         return(-1);
242     }
243     wsttab[wstnlun] = t;
244     bzero(t, sizeof(struct wst));
245     bufq_init(&t->buf_queue);
246     t->ata = ata;
247     t->unit = unit;
248     t->ata->use_dsc = 1;
249     lun = t->lun = wstnlun;
250     t->param = ap;
251     t->flags = WST_MEDIA_CHANGED | WST_DEBUG;
252
253     if (wst_sense(t))
254         return -1;
255
256     wst_describe(t);
257     wstnlun++;
258
259     make_dev(&wst_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0640, "rwst%d", t->lun);
260     return(1);
261 }
262
263 static int 
264 wst_sense(struct wst *t)
265 {
266     struct atapires result;
267     int count;
268     char buffer[255];
269
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 */
275             ATAPI_TAPE_CAP_PAGE,
276             sizeof(buffer)>>8, sizeof(buffer),
277             0, 0, 0, 0, 0, 0, 0,
278             0, 0, 0, 0, buffer, sizeof(buffer));
279         if (result.code == 0 || result.code == RES_UNDERRUN)
280             break;
281     }
282
283     /* Some drives have shorter capabilities page. */
284     if (result.code == RES_UNDERRUN)
285         result.code = 0;
286
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)
292             return 1;   
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));
299         return 0;
300     }
301     return 1;
302 }
303
304 static void 
305 wst_describe(struct wst *t)
306 {
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);
313     }
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);
332     printf("\n");
333 }
334
335 int
336 wstopen(dev_t dev, int flags, int fmt, struct proc *p)
337 {
338     int lun = UNIT(dev);
339     struct wst *t;
340
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);
345         return(ENXIO);
346     }
347     t = wsttab[lun];
348     if (t->flags == WST_OPEN)
349         return EBUSY;
350     if (wst_sense(t))
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;
355     return(0);
356 }
357
358 int 
359 wstclose(dev_t dev, int flags, int fmt, struct proc *p)
360 {
361     int lun = UNIT(dev);
362     struct wst *t = wsttab[lun];
363
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);
367
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);
371
372     /* If minor is even rewind on close */
373     if (!(minor(dev) & 0x01))   
374         wst_rewind(t);
375
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;
380     return(0);
381 }
382
383 void 
384 wststrategy(struct buf *bp)
385 {
386     int lun = UNIT(bp->b_dev);
387     struct wst *t = wsttab[lun];
388     int x;
389
390     /* If it's a null transfer, return immediatly. */
391     if (bp->b_bcount == 0) {
392         bp->b_resid = 0;
393         biodone(bp);
394         return;
395     }
396
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);
400         bp->b_error = EIO;
401         bp->b_flags |= B_ERROR;
402         biodone(bp);
403         return;
404     }
405
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;
411         }
412     }
413
414     x = splbio();
415     wst_total += bp->b_bcount;
416     bufq_insert_tail(&t->buf_queue, bp);
417     wst_start(t);
418     splx(x);
419 }
420
421 static void     
422 wst_poll_dsc(struct wst *t)
423
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);
427         return;
428     }       
429     t->ata->wait_for_dsc = 0;
430     wakeup((caddr_t)t);
431 }
432
433 static void 
434 wst_start(struct wst *t)
435 {
436     struct buf *bp = bufq_first(&t->buf_queue);
437     u_long blk_count;
438     u_char op_code;
439     long byte_count;
440     
441     if (!bp)
442         return;
443
444     if (t->ata->wait_for_dsc)
445         printf("wst%d: ERROR! allready waiting for DSC\n", t->lun);
446
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);
452     }
453
454     bufq_remove(&t->buf_queue, bp);
455     blk_count = bp->b_bcount / t->blksize;
456
457     if (bp->b_flags & B_READ) {
458         op_code = ATAPI_TAPE_READ_CMD;
459         byte_count = bp->b_bcount;
460     } else {
461         op_code = ATAPI_TAPE_WRITE_CMD;
462         t->flags |= WST_DATA_WRITTEN;
463         byte_count = -bp->b_bcount;
464     }
465
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);
471 }
472
473 static void 
474 wst_done(struct wst *t, struct buf *bp, int resid,
475     struct atapires result)
476 {
477     if (result.code) {
478         printf("wst_done: ");
479         wst_error(t, result);
480         bp->b_error = EIO;
481         bp->b_flags |= B_ERROR;
482     }
483     else
484         bp->b_resid = resid;
485
486     biodone(bp);
487     /*wst_start(t);*/
488 }
489
490 static int 
491 wst_error(struct wst *t, struct atapires result)
492 {
493     struct wst_reqsense sense;
494
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);
498         return 1;
499     }
500
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),
505             0, 0, 0, 0, 0, 0, 0,
506             0, 0, 0, 0, (char*) &sense, sizeof(struct wst_reqsense));
507         /*wst_dump(t->lun, "req_sense", &sense, sizeof(struct wst_reqsense));*/
508     }
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);
514             break;
515         }
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;
520         break;
521
522     case AER_SK_BLANK_CHECK:
523         if (t->flags & WST_DEBUG)
524             printf("wst%d: EOD encountered\n", t->lun);
525         break;
526
527     case AER_SK_MEDIUM_ERROR:
528         if (t->flags & WST_DEBUG)
529             printf("wst%d: nonrecovered data error\n", t->lun);
530         break;
531
532     case AER_SK_HARDWARE_ERROR:
533         if (t->flags & WST_DEBUG)
534             printf("wst%d: nonrecovered hardware error\n", t->lun);
535         break;
536
537     case AER_SK_ILLEGAL_REQUEST:
538         if (t->flags & WST_DEBUG)
539             printf("wst%d: invalid command\n", t->lun);
540         break;
541
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;
546         break;
547
548     case AER_SK_DATA_PROTECT:
549         if (t->flags & WST_DEBUG)
550             printf("wst%d: reading read protected data\n", t->lun);
551         break;
552
553     case AER_SK_ABORTED_COMMAND:
554         if (t->flags & WST_DEBUG)
555             printf("wst%d: command aborted\n", t->lun);
556         break;
557
558     case AER_SK_MISCOMPARE:
559         if (t->flags & WST_DEBUG)
560             printf("wst%d: data don't match medium\n", t->lun);
561         break;
562
563     default:
564         printf("wst%d: i/o error, status=%b, error=%b\n", t->lun,
565                 result.status, ARS_BITS, result.error, AER_BITS);
566     }
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);
570     return 1;
571 }
572
573 int 
574 wstioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
575 {
576     int lun = UNIT(dev);
577     int error = 0;
578     struct wst *t = wsttab[lun];
579
580     switch (cmd) {
581     case MTIOCGET:
582         {
583             struct mtget *g = (struct mtget *) addr;
584
585             bzero(g, sizeof(struct mtget));
586             g->mt_type = 7;
587             g->mt_density = 1;
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;
596             break;       
597         }
598     case MTIOCTOP:
599         {       
600             int i;
601             struct mtop *mt = (struct mtop *)addr;
602
603             switch ((short) (mt->mt_op)) {
604             case MTWEOF:
605                 for (i=0; i < mt->mt_count && !error; i++)
606                         error = wst_write_filemark(t, WEOF_WRITE_MASK);
607                 break;
608             case MTFSF:
609                 if (mt->mt_count)
610                         error = wst_space_cmd(t, SP_FM, mt->mt_count);
611                 break;
612             case MTBSF:
613                 if (mt->mt_count)
614                         error = wst_space_cmd(t, SP_FM, -(mt->mt_count));
615                 break;
616             case MTFSR:
617                 error = EINVAL; break;
618             case MTBSR:
619                 error = EINVAL; break;
620             case MTREW:
621                 error = wst_rewind(t);
622                 break;
623             case MTOFFL:
624 #if 1                           /* Misuse as a reset func for now */
625                 wst_reset(t);
626                 wst_sense(t);
627                 wst_describe(t);
628 #else
629                 if (error = wst_rewind(t))
630                     break;
631                 error = wst_load_unload(t, !LU_LOAD_MASK);
632 #endif
633                     break;
634             case MTNOP:
635                 error = wst_write_filemark(t, 0);
636                 break;
637             case MTCACHE:
638                 error = EINVAL; break;
639             case MTNOCACHE:
640                 error = EINVAL; break;
641             case MTSETBSIZ:
642                 error = EINVAL; break;
643             case MTSETDNSTY:
644                 error = EINVAL; break;
645             case MTERASE:
646                 error = wst_erase(t);
647                 break;
648             case MTEOD:
649                 error = wst_space_cmd(t, SP_EOD, 0);
650                 break;
651             case MTCOMP:
652                 error = EINVAL; break;
653             case MTRETENS:
654                 error = wst_load_unload(t, LU_RETENSION_MASK|LU_LOAD_MASK);
655                 break;
656             default:
657                 error = EINVAL;
658             }
659             return error;
660         }
661     default:
662         return(ENOTTY);
663     }
664     return(error);
665 }
666
667 static int
668 wst_space_cmd(struct wst *t, u_char function, u_int count)
669 {
670     struct atapires result;
671
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);
676     if (result.code) {
677         printf("wst_space_cmd: ");
678         wst_error(t, result);
679         return EIO;
680     }
681     return 0;
682 }
683
684 static int
685 wst_write_filemark(struct wst *t, u_char function)
686 {
687     struct atapires result;
688
689     if (function) {
690         if (t->flags & WST_FM_WRITTEN)
691             t->flags &= ~WST_DATA_WRITTEN;
692         else
693             t->flags |= WST_FM_WRITTEN;
694     }
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);
698     if (result.code) {
699         printf("wst_write_filemark: ");
700         wst_error(t, result);
701         return EIO;
702     }
703     return 0;
704 }
705
706 static int
707 wst_load_unload(struct wst *t, u_char function)
708 {
709     struct atapires result;
710
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);
714     if (result.code) {
715         printf("wst_load_unload: ");
716         wst_error(t, result);
717         return EIO;
718     }
719     return 0;
720 }
721
722 static int
723 wst_erase(struct wst *t)
724 {
725     int error;
726     struct atapires result;
727
728     error = wst_rewind(t);
729     if (error)
730         return error;
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,
734                                 NULL, 0);
735     if (result.code) {
736         printf("wst_erase: ");
737         wst_error(t, result);
738         return EIO;
739     }
740     return 0;
741 }
742
743 static int
744 wst_rewind(struct wst *t)
745 {
746     struct atapires result;       
747
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,
751                                     NULL, 0);
752     if (result.code) {
753         printf("wst_rewind: ");
754         wst_error(t, result);
755         return EIO;
756     }
757     return 0;
758 }
759
760 static void
761 wst_reset(struct wst *t)
762 {
763     outb(t->ata->port + AR_DRIVE, ARD_DRIVE1);
764     DELAY(30);
765     outb(t->ata->port + AR_COMMAND, 0x08);
766     DELAY(30);
767 }
768
769 static void 
770 wst_drvinit(void *unused)
771 {
772     cdevsw_add(&wst_cdevsw);
773 }
774
775 SYSINIT(wstdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wst_drvinit,NULL)