]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ata/atapi-tape.c
Add support for the VIA 8235.
[FreeBSD/FreeBSD.git] / sys / dev / ata / atapi-tape.c
1 /*-
2  * Copyright (c) 1998,1999,2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
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 "opt_ata.h"
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/ata.h>
35 #include <sys/kernel.h>
36 #include <sys/conf.h>
37 #include <sys/malloc.h>
38 #include <sys/bio.h>
39 #include <sys/bus.h>
40 #include <sys/mtio.h>
41 #include <sys/disklabel.h>
42 #include <sys/devicestat.h>
43 #include <machine/bus.h>
44 #include <dev/ata/ata-all.h>
45 #include <dev/ata/atapi-all.h>
46 #include <dev/ata/atapi-tape.h>
47
48 /* device structures */
49 static  d_open_t        astopen;
50 static  d_close_t       astclose;
51 static  d_ioctl_t       astioctl;
52 static  d_strategy_t    aststrategy;
53 static struct cdevsw ast_cdevsw = {
54         /* open */      astopen,
55         /* close */     astclose,
56         /* read */      physread,
57         /* write */     physwrite,
58         /* ioctl */     astioctl,
59         /* poll */      nopoll,
60         /* mmap */      nommap,
61         /* strategy */  aststrategy,
62         /* name */      "ast",
63         /* maj */       119,
64         /* dump */      nodump,
65         /* psize */     nopsize,
66         /* flags */     D_TAPE | D_TRACKCLOSE,
67 };
68
69 /* prototypes */
70 static int ast_sense(struct ast_softc *);
71 static void ast_describe(struct ast_softc *);
72 static int ast_done(struct atapi_request *);
73 static int ast_mode_sense(struct ast_softc *, int, void *, int); 
74 static int ast_mode_select(struct ast_softc *, void *, int);
75 static int ast_write_filemark(struct ast_softc *, u_int8_t);
76 static int ast_read_position(struct ast_softc *, int, struct ast_readposition *);
77 static int ast_space(struct ast_softc *, u_int8_t, int32_t);
78 static int ast_locate(struct ast_softc *, int, u_int32_t);
79 static int ast_prevent_allow(struct ast_softc *stp, int);
80 static int ast_load_unload(struct ast_softc *, u_int8_t);
81 static int ast_rewind(struct ast_softc *);
82 static int ast_erase(struct ast_softc *);
83
84 /* internal vars */
85 static u_int32_t ast_lun_map = 0;
86 static u_int64_t ast_total = 0;
87 static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers");
88
89 int 
90 astattach(struct ata_device *atadev)
91 {
92     struct ast_softc *stp;
93     struct ast_readposition position;
94     dev_t dev;
95
96     stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO);
97     if (!stp) {
98         ata_prtdev(atadev, "out of memory\n");
99         return 0;
100     }
101
102     stp->device = atadev;
103     stp->lun = ata_get_lun(&ast_lun_map);
104     ata_set_name(atadev, "ast", stp->lun);
105     bioq_init(&stp->queue);
106
107     if (ast_sense(stp)) {
108         free(stp, M_AST);
109         return 0;
110     }
111
112     if (!strcmp(atadev->param->model, "OnStream DI-30")) {
113         struct ast_transferpage transfer;
114         struct ast_identifypage identify;
115
116         stp->flags |= F_ONSTREAM;
117         bzero(&transfer, sizeof(struct ast_transferpage));
118         ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE,
119                        &transfer, sizeof(transfer));
120         bzero(&identify, sizeof(struct ast_identifypage));
121         ast_mode_sense(stp, ATAPI_TAPE_IDENTIFY_PAGE,
122                        &identify, sizeof(identify));
123         strncpy(identify.ident, "FBSD", 4);
124         ast_mode_select(stp, &identify, sizeof(identify));
125         ast_read_position(stp, 0, &position);
126     }
127
128     devstat_add_entry(&stp->stats, "ast", stp->lun, DEV_BSIZE,
129                       DEVSTAT_NO_ORDERED_TAGS,
130                       DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
131                       DEVSTAT_PRIORITY_TAPE);
132     dev = make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0, 0),
133                    UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun);
134     dev->si_drv1 = stp;
135     dev->si_iosize_max = 256 * DEV_BSIZE;
136     stp->dev1 = dev;
137     dev = make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0, 1),
138                    UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun);
139     dev->si_drv1 = stp;
140     dev->si_iosize_max = 256 * DEV_BSIZE;
141     stp->dev2 = dev;
142     stp->device->flags |= ATA_D_MEDIA_CHANGED;
143     ast_describe(stp);
144     atadev->driver = stp;
145     return 1;
146 }
147
148 void    
149 astdetach(struct ata_device *atadev)
150 {   
151     struct ast_softc *stp = atadev->driver;
152     struct bio *bp;
153     
154     while ((bp = bioq_first(&stp->queue))) {
155         bioq_remove(&stp->queue, bp);
156         biofinish(bp, NULL, ENXIO);
157     }
158     destroy_dev(stp->dev1);
159     destroy_dev(stp->dev2);
160     devstat_remove_entry(&stp->stats);
161     ata_free_name(atadev);
162     ata_free_lun(&ast_lun_map, stp->lun);
163     free(stp, M_AST);
164     atadev->driver = NULL;
165 }
166
167 static int
168 ast_sense(struct ast_softc *stp)
169 {
170     int count, error = 0;
171
172     /* get drive capabilities, some drives needs this repeated */
173     for (count = 0 ; count < 5 ; count++) {
174         if (!(error = ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE,
175                                      &stp->cap, sizeof(stp->cap)))) {
176             if (stp->cap.blk32k)
177                 stp->blksize = 32768;
178             if (stp->cap.blk1024)
179                 stp->blksize = 1024;
180             if (stp->cap.blk512)
181                 stp->blksize = 512;
182             if (!stp->blksize)
183                 continue;
184             stp->cap.max_speed = ntohs(stp->cap.max_speed);
185             stp->cap.max_defects = ntohs(stp->cap.max_defects);
186             stp->cap.ctl = ntohs(stp->cap.ctl);
187             stp->cap.speed = ntohs(stp->cap.speed);
188             stp->cap.buffer_size = ntohs(stp->cap.buffer_size);
189             return 0;
190         }
191     }
192     return 1;
193 }
194
195 static void 
196 ast_describe(struct ast_softc *stp)
197 {
198     if (bootverbose) {
199         ata_prtdev(stp->device, "<%.40s/%.8s> tape drive at ata%d as %s\n",
200                    stp->device->param->model, stp->device->param->revision,
201                    device_get_unit(stp->device->channel->dev),
202                    (stp->device->unit == ATA_MASTER) ? "master" : "slave");
203         ata_prtdev(stp->device, "%dKB/s, ", stp->cap.max_speed);
204         printf("transfer limit %d blk%s, ",
205                stp->cap.ctl, (stp->cap.ctl > 1) ? "s" : "");
206         printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024);
207         printf("%s\n", ata_mode2str(stp->device->mode));
208         ata_prtdev(stp->device, "Medium: ");
209         switch (stp->cap.medium_type) {
210             case 0x00:
211                 printf("none"); break;
212             case 0x17:
213                 printf("Travan 1 (400 Mbyte)"); break;
214             case 0xb6:
215                 printf("Travan 4 (4 Gbyte)"); break;
216             case 0xda:
217                 printf("OnStream ADR (15Gyte)"); break;
218             default:
219                 printf("unknown (0x%x)", stp->cap.medium_type);
220         }
221         if (stp->cap.readonly) printf(", readonly");
222         if (stp->cap.reverse) printf(", reverse");
223         if (stp->cap.eformat) printf(", eformat");
224         if (stp->cap.qfa) printf(", qfa");
225         if (stp->cap.lock) printf(", lock");
226         if (stp->cap.locked) printf(", locked");
227         if (stp->cap.prevent) printf(", prevent");
228         if (stp->cap.eject) printf(", eject");
229         if (stp->cap.disconnect) printf(", disconnect");
230         if (stp->cap.ecc) printf(", ecc");
231         if (stp->cap.compress) printf(", compress");
232         if (stp->cap.blk512) printf(", 512b");
233         if (stp->cap.blk1024) printf(", 1024b");
234         if (stp->cap.blk32k) printf(", 32kb");
235         printf("\n");
236     }
237     else {
238         ata_prtdev(stp->device, "TAPE <%.40s> at ata%d-%s %s\n",
239                    stp->device->param->model,
240                    device_get_unit(stp->device->channel->dev),
241                    (stp->device->unit == ATA_MASTER) ? "master" : "slave",
242                    ata_mode2str(stp->device->mode));
243     }
244 }
245
246 static int
247 astopen(dev_t dev, int flags, int fmt, struct thread *td)
248 {
249     struct ast_softc *stp = dev->si_drv1;
250
251     if (!stp)
252         return ENXIO;
253
254     if (count_dev(dev) > 1)
255         return EBUSY;
256
257     atapi_test_ready(stp->device);
258
259     if (stp->cap.lock)
260         ast_prevent_allow(stp, 1);
261
262     if (ast_sense(stp))
263         ata_prtdev(stp->device, "sense media type failed\n");
264
265     stp->device->flags &= ~ATA_D_MEDIA_CHANGED;
266     stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN);
267     ast_total = 0;
268     return 0;
269 }
270
271 static int 
272 astclose(dev_t dev, int flags, int fmt, struct thread *td)
273 {
274     struct ast_softc *stp = dev->si_drv1;
275
276     /* flush buffers, some drives fail here, they should report ctl = 0 */
277     if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN))
278         ast_write_filemark(stp, 0);
279
280     /* write filemark if data written to tape */
281     if (!(stp->flags & F_ONSTREAM) &&
282         (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN)
283         ast_write_filemark(stp, WF_WRITE);
284
285     /* if minor is even rewind on close */
286     if (!(minor(dev) & 0x01))
287         ast_rewind(stp);
288
289     if (stp->cap.lock && count_dev(dev) == 1)
290         ast_prevent_allow(stp, 0);
291
292     stp->flags &= F_CTL_WARN;
293 #ifdef AST_DEBUG
294     ata_prtdev(stp->device, "%llu total bytes transferred\n", ast_total);
295 #endif
296     return 0;
297 }
298
299 static int 
300 astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
301 {
302     struct ast_softc *stp = dev->si_drv1;
303     int error = 0;
304
305     switch (cmd) {
306     case MTIOCGET:
307         {
308             struct mtget *g = (struct mtget *) addr;
309
310             bzero(g, sizeof(struct mtget));
311             g->mt_type = 7;
312             g->mt_density = 1;
313             g->mt_blksiz = stp->blksize;
314             g->mt_comp = stp->cap.compress;
315             g->mt_density0 = 0; g->mt_density1 = 0;
316             g->mt_density2 = 0; g->mt_density3 = 0;
317             g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
318             g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
319             g->mt_comp0 = 0; g->mt_comp1 = 0;
320             g->mt_comp2 = 0; g->mt_comp3 = 0;
321             break;       
322         }
323     case MTIOCTOP:
324         {       
325             int i;
326             struct mtop *mt = (struct mtop *)addr;
327
328             switch ((int16_t) (mt->mt_op)) {
329
330             case MTWEOF:
331                 for (i=0; i < mt->mt_count && !error; i++)
332                     error = ast_write_filemark(stp, WF_WRITE);
333                 break;
334
335             case MTFSF:
336                 if (mt->mt_count)
337                     error = ast_space(stp, SP_FM, mt->mt_count);
338                 break;
339
340             case MTBSF:
341                 if (mt->mt_count)
342                     error = ast_space(stp, SP_FM, -(mt->mt_count));
343                 break;
344
345             case MTREW:
346                 error = ast_rewind(stp);
347                 break;
348
349             case MTOFFL:
350                 error = ast_load_unload(stp, SS_EJECT);
351                 break;
352
353             case MTNOP:
354                 error = ast_write_filemark(stp, 0);
355                 break;
356
357             case MTERASE:
358                 error = ast_erase(stp);
359                 break;
360
361             case MTEOD:
362                 error = ast_space(stp, SP_EOD, 0);
363                 break;
364
365             case MTRETENS:
366                 error = ast_load_unload(stp, SS_RETENSION | SS_LOAD);
367                 break;
368
369             case MTFSR:         
370             case MTBSR:
371             case MTCACHE:
372             case MTNOCACHE:
373             case MTSETBSIZ:
374             case MTSETDNSTY:
375             case MTCOMP:
376             default:
377                 error = EINVAL;
378             }
379             break;
380         }
381     case MTIOCRDSPOS:
382         {
383             struct ast_readposition position;
384
385             if ((error = ast_read_position(stp, 0, &position)))
386                 break;
387             *(u_int32_t *)addr = position.tape;
388             break;
389         }
390     case MTIOCRDHPOS:
391         {
392             struct ast_readposition position;
393
394             if ((error = ast_read_position(stp, 1, &position)))
395                 break;
396             *(u_int32_t *)addr = position.tape;
397             break;
398         }
399     case MTIOCSLOCATE:
400         error = ast_locate(stp, 0, *(u_int32_t *)addr);
401         break;
402     case MTIOCHLOCATE:
403         error = ast_locate(stp, 1, *(u_int32_t *)addr);
404         break;
405     default:
406         error = ENOTTY;
407     }
408     return error;
409 }
410
411 static void 
412 aststrategy(struct bio *bp)
413 {
414     struct ast_softc *stp = bp->bio_dev->si_drv1;
415     int s;
416
417     if (stp->device->flags & ATA_D_DETACHING) {
418         biofinish(bp, NULL, ENXIO);
419         return;
420     }
421
422     /* if it's a null transfer, return immediatly. */
423     if (bp->bio_bcount == 0) {
424         bp->bio_resid = 0;
425         biodone(bp);
426         return;
427     }
428     if (!(bp->bio_cmd == BIO_READ) && stp->flags & F_WRITEPROTECT) {
429         biofinish(bp, NULL, EPERM);
430         return;
431     }
432         
433     /* check for != blocksize requests */
434     if (bp->bio_bcount % stp->blksize) {
435         ata_prtdev(stp->device, "transfers must be multiple of %d\n",
436                    stp->blksize);
437         biofinish(bp, NULL, EIO);
438         return;
439     }
440
441     /* warn about transfers bigger than the device suggests */
442     if (bp->bio_bcount > stp->blksize * stp->cap.ctl) {  
443         if ((stp->flags & F_CTL_WARN) == 0) {
444             ata_prtdev(stp->device, "WARNING: CTL exceeded %ld>%d\n",
445                        bp->bio_bcount, stp->blksize * stp->cap.ctl);
446             stp->flags |= F_CTL_WARN;
447         }
448     }
449
450     s = splbio();
451     bioq_insert_tail(&stp->queue, bp);
452     splx(s);
453     ata_start(stp->device->channel);
454 }
455
456 void 
457 ast_start(struct ata_device *atadev)
458 {
459     struct ast_softc *stp = atadev->driver;
460     struct bio *bp = bioq_first(&stp->queue);
461     u_int32_t blkcount;
462     int8_t ccb[16];
463     
464     if (!bp)
465         return;
466
467     bzero(ccb, sizeof(ccb));
468
469     if (bp->bio_cmd == BIO_READ)
470         ccb[0] = ATAPI_READ;
471     else
472         ccb[0] = ATAPI_WRITE;
473     
474     bioq_remove(&stp->queue, bp);
475     blkcount = bp->bio_bcount / stp->blksize;
476
477     ccb[1] = 1;
478     ccb[2] = blkcount>>16;
479     ccb[3] = blkcount>>8;
480     ccb[4] = blkcount;
481
482     devstat_start_transaction(&stp->stats);
483
484     atapi_queue_cmd(stp->device, ccb, bp->bio_data, blkcount * stp->blksize, 
485                     (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0,
486                     120, ast_done, bp);
487 }
488
489 static int 
490 ast_done(struct atapi_request *request)
491 {
492     struct bio *bp = request->driver;
493     struct ast_softc *stp = request->device->driver;
494
495     if (request->error) {
496         bp->bio_error = request->error;
497         bp->bio_flags |= BIO_ERROR;
498     }
499     else {
500         if (!(bp->bio_cmd == BIO_READ))
501             stp->flags |= F_DATA_WRITTEN;
502         bp->bio_resid = bp->bio_bcount - request->donecount;
503         ast_total += (bp->bio_bcount - bp->bio_resid);
504     }
505     biofinish(bp, &stp->stats, 0);
506     return 0;
507 }
508
509 static int
510 ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize)
511 {
512     int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize,
513                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
514     int error;
515  
516     error = atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, ATPR_F_READ,
517                             10, NULL, NULL);
518 #ifdef AST_DEBUG
519     atapi_dump("ast: mode sense ", pagebuf, pagesize);
520 #endif
521     return error;
522 }
523
524 static int       
525 ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize)
526 {
527     int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize,
528                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
529      
530 #ifdef AST_DEBUG
531     ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize);
532     atapi_dump("mode select ", pagebuf, pagesize);
533 #endif
534     return atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, 0,
535                            10, NULL, NULL);
536 }
537
538 static int
539 ast_write_filemark(struct ast_softc *stp, u_int8_t function)
540 {
541     int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0,
542                        0, 0, 0, 0, 0, 0, 0, 0 };
543     int error;
544
545     if (stp->flags & F_ONSTREAM)
546         ccb[4] = 0x00;          /* only flush buffers supported */
547     else {
548         if (function) {
549             if (stp->flags & F_FM_WRITTEN)
550                 stp->flags &= ~F_DATA_WRITTEN;
551             else
552                 stp->flags |= F_FM_WRITTEN;
553         }
554     }
555     error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
556     if (error)
557         return error;
558     return atapi_wait_dsc(stp->device, 10*60);
559 }
560
561 static int
562 ast_read_position(struct ast_softc *stp, int hard,
563                   struct ast_readposition *position)
564 {
565     int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0,
566                        0, 0, 0, 0, 0, 0, 0, 0 };
567     int error;
568
569     error = atapi_queue_cmd(stp->device, ccb, (caddr_t)position, 
570                             sizeof(struct ast_readposition), ATPR_F_READ, 10,
571                             NULL, NULL);
572     position->tape = ntohl(position->tape);
573     position->host = ntohl(position->host);
574     return error;
575 }
576
577 static int
578 ast_space(struct ast_softc *stp, u_int8_t function, int32_t count)
579 {
580     int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count,
581                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
582
583     return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL);
584 }
585
586 static int
587 ast_locate(struct ast_softc *stp, int hard, u_int32_t pos)
588 {
589     int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0,
590                        pos>>24, pos>>16, pos>>8, pos,
591                        0, 0, 0, 0, 0, 0, 0, 0, 0 };
592     int error;
593
594     error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
595     if (error)
596         return error;
597     return atapi_wait_dsc(stp->device, 60*60);
598 }
599
600 static int
601 ast_prevent_allow(struct ast_softc *stp, int lock)
602 {
603     int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
604                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
605
606     return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0,30, NULL, NULL);
607 }
608
609 static int
610 ast_load_unload(struct ast_softc *stp, u_int8_t function)
611 {
612     int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0,
613                        0, 0, 0, 0, 0, 0, 0, 0 };
614     int error;
615
616     if ((function & SS_EJECT) && !stp->cap.eject)
617         return 0;
618     error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
619     if (error)
620         return error;
621     tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz);
622     if (function == SS_EJECT)
623         return 0;
624     return atapi_wait_dsc(stp->device, 60*60);
625 }
626
627 static int
628 ast_rewind(struct ast_softc *stp)
629 {
630     int8_t ccb[16] = { ATAPI_REZERO, 0x01, 0, 0, 0, 0, 0, 0,
631                        0, 0, 0, 0, 0, 0, 0, 0 };
632     int error;
633
634     error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
635     if (error)
636         return error;
637     return atapi_wait_dsc(stp->device, 60*60);
638 }
639
640 static int
641 ast_erase(struct ast_softc *stp)
642 {
643     int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0,
644                        0, 0, 0, 0, 0, 0, 0, 0 };
645     int error;
646
647     if ((error = ast_rewind(stp)))
648         return error;
649
650     return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL);
651 }