Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / readom / readom.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)readcd.c 1.80 06/02/05 Copyright 1987, 1995-2006 J. Schilling */
14 /*
15  *      Skeleton for the use of the usal genearal SCSI - driver
16  *
17  *      Copyright (c) 1987, 1995-2004 J. Schilling
18  */
19 /*
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2
22  * as published by the Free Software Foundation.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along with
30  * this program; see the file COPYING.  If not, write to the Free Software
31  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33
34 #include <mconfig.h>
35 #include <stdio.h>
36 #include <standard.h>
37 #include <unixstd.h>
38 #include <stdxlib.h>
39 #include <strdefs.h>
40 #include <fctldefs.h>
41 #include <timedefs.h>
42 #include <signal.h>
43 #include <schily.h>
44 #ifdef  HAVE_PRIV_H
45 #include <priv.h>
46 #endif
47
48 #ifdef  NEED_O_BINARY
49 #include <io.h>                                 /* for setmode() prototype */
50 #endif
51
52 #include <usal/usalcmd.h>
53 #include <usal/scsireg.h>
54 #include <usal/scsitransp.h>
55
56 #include "scsi_scan.h"
57 #include "scsimmc.h"
58 #define qpto96  __nothing__
59 #include "wodim.h"
60 #include "defaults.h"
61 #undef  qpto96
62 #include "movesect.h"
63
64 char    cdr_version[] = "2.01.01a05";
65
66 #if     defined(PROTOTYPES)
67 #define UINT_C(a)       (a##u)
68 #define ULONG_C(a)      (a##ul)
69 #define USHORT_C(a)     (a##uh)
70 #define CONCAT(a, b)    a##b
71 #else
72 #define UINT_C(a)       ((unsigned)(a))
73 #define ULONG_C(a)      ((unsigned long)(a))
74 #define USHORT_C(a)     ((unsigned short)(a))
75 /* CSTYLED */
76 #define CONCAT(a, b)    a/**/b
77 #endif
78
79 extern  BOOL    getlong(char *, long *, long, long);
80 extern  BOOL    getint(char *, int *, int, int);
81
82 typedef struct {
83         long    start;
84         long    end;
85         long    sptr;           /* sectors per transfer */
86         BOOL    askrange;
87         char    *name;
88 } parm_t;
89
90 typedef struct {
91         int     errors;
92         int     c2_errors;
93         int     c2_maxerrs;
94         int     c2_errsecs;
95         int     c2_badsecs;
96         int     secsize;
97         BOOL    ismmc;
98 } rparm_t;
99
100 struct exargs {
101         SCSI    *usalp;
102         int     old_secsize;
103         int     flags;
104         int     exflags;
105         char    oerr[3];
106 } exargs;
107
108 BOOL    cvt_cyls(void);
109 BOOL    cvt_bcyls(void);
110 void    print_defect_list(void);
111 static  void    usage(int ret);
112 static  void    intr(int sig);
113 static  void    exscsi(int excode, void *arg);
114 static  void    excdr(int excode, void *arg);
115 static  int     prstats(void);
116 static  int     prstats_silent(void);
117 static  void    dorw(SCSI *usalp, char *filename, char *sectors);
118 static  void    doit(SCSI *usalp);
119 static  void    read_disk(SCSI *usalp, parm_t *parmp);
120 #ifdef  CLONE_WRITE
121 static  void    readcd_disk(SCSI *usalp, parm_t *parmp);
122 static  void    read_lin(SCSI *usalp, parm_t *parmp);
123 static  int     read_secheader(SCSI *usalp, long addr);
124 static  int     read_ftoc(SCSI *usalp, parm_t *parmp, BOOL do_sectype);
125 static  void    read_sectypes(SCSI *usalp, FILE *f);
126 static  void    get_sectype(SCSI *usalp, long addr, char *st);
127 #endif
128
129 static  void    readc2_disk(SCSI *usalp, parm_t *parmp);
130 static  int     fread_data(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, 
131                                                                   int cnt);
132 #ifdef  CLONE_WRITE
133 static  int     fread_2448(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, 
134                                                                   int cnt);
135 static  int     fread_2448_16(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, 
136                                                                           int cnt);
137 static  int     fread_2352(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, 
138                                                                   int cnt);
139 static  int     fread_lin(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, 
140                                                                  int cnt);
141 #endif
142 static  int     bits(int c);
143 static  int     bitidx(int c);
144 static  int     fread_c2(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, 
145                                                                 int cnt);
146
147 static  int     fdata_null(rparm_t *rp, caddr_t bp, long addr, int cnt);
148 static  int     fdata_c2(rparm_t *rp, caddr_t bp, long addr, int cnt);
149
150 #ifdef  used
151 static  int read_scsi_g1(SCSI *usalp, caddr_t bp, long addr, int cnt);
152 #endif
153
154 int     write_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt);
155 int     write_g0(SCSI *usalp, caddr_t bp, long addr, int cnt);
156 int     write_g1(SCSI *usalp, caddr_t bp, long addr, int cnt);
157
158 #ifdef  used
159 static  void    Xrequest_sense(SCSI *usalp);
160 #endif
161 static  int     read_retry(SCSI *usalp, caddr_t bp, long addr, long cnt,
162                                                                   int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt),
163                                                                   rparm_t *rp);
164 static  void    read_generic(SCSI *usalp, parm_t *parmp,
165                                                                          int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt),
166                                                                          rparm_t *rp,
167                                                                          int (*dfunc)(rparm_t *rp, caddr_t bp, long addr, int cnt));
168 static  void    write_disk(SCSI *usalp, parm_t *parmp);
169 static  int     choice(int n);
170 static  void    ra(SCSI *usalp);
171
172 int     read_da(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, 
173                                   int subcode);
174 int     read_cd(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, 
175                                   int data, int subch);
176
177 static  void    oldmode(SCSI *usalp, int *errp, int *retrp);
178 static  void    domode(SCSI *usalp, int err, int retr);
179
180 static  void    qpto96(Uchar *sub, Uchar *subq, int dop);
181 static  void    ovtime(SCSI *usalp);
182 static  void    add_bad(long addr);
183 static  void    print_bad(void);
184
185 struct timeval  starttime;
186 struct timeval  stoptime;
187 int     didintr;
188 int     exsig;
189
190 char    *Sbuf;
191 long    Sbufsize;
192
193 /*#define       MAX_RETRY       32*/
194 #define MAX_RETRY       128
195
196 int     help;
197 int     xdebug;
198 int     lverbose;
199 int     quiet;
200 BOOL    is_suid;
201 BOOL    is_cdrom;
202 BOOL    is_dvd;
203 BOOL    do_write;
204 BOOL    c2scan;
205 BOOL    fulltoc;
206 BOOL    clonemode;
207 BOOL    noerror;
208 BOOL    nocorr;
209 BOOL    notrunc;
210 int     retries = MAX_RETRY;
211 int     maxtry = 0;
212 int     meshpoints;
213 BOOL    do_factor;
214
215 struct  scsi_format_data fmt;
216
217 /*XXX*/EXPORT   BOOL cvt_cyls(void) { return (FALSE); }
218 /*XXX*/EXPORT   BOOL cvt_bcyls(void) { return (FALSE); }
219 /*XXX*/EXPORT   void print_defect_list(void) {}
220
221 static void
222 usage(int ret)
223 {
224         fprintf(stderr, "Usage:\treadom [options]\n");
225         fprintf(stderr, "options:\n");
226         fprintf(stderr, "\t-version     print version information and exit\n");
227         fprintf(stderr, "\tdev=target   SCSI target to use\n");
228         fprintf(stderr, "\tf=filename   Name of file to read/write\n");
229         fprintf(stderr, "\tsectors=range        Range of sectors to read/write\n");
230         fprintf(stderr, "\tspeed=#              set speed of drive (MMC only)\n");
231         fprintf(stderr, "\tts=#         set maximum transfer size for a single SCSI command\n");
232         fprintf(stderr, "\t-w           Switch to write mode\n");
233         fprintf(stderr, "\t-c2scan              Do a C2 error scan\n");
234 #ifdef  CLONE_WRITE
235         fprintf(stderr, "\t-fulltoc     Retrieve the full TOC\n");
236         fprintf(stderr, "\t-clone               Retrieve the full TOC and all data\n");
237 #endif
238         fprintf(stderr, "\ttimeout=#    set the default SCSI command timeout to #.\n");
239         fprintf(stderr, "\tdebug=#,-d   Set to # or increment misc debug level\n");
240         fprintf(stderr, "\tkdebug=#,kd=#        do Kernel debugging\n");
241         fprintf(stderr, "\t-quiet,-q    be more quiet in error retry mode\n");
242         fprintf(stderr, "\t-verbose,-v  increment general verbose level by one\n");
243         fprintf(stderr, "\t-Verbose,-V  increment SCSI command transport verbose level by one\n");
244         fprintf(stderr, "\t-silent,-s   do not print status of failed SCSI commands\n");
245         fprintf(stderr, "\t-scanbus     scan the SCSI bus and exit\n");
246         fprintf(stderr, "\t-noerror     do not abort on error\n");
247 #ifdef  CLONE_WRITE
248         fprintf(stderr, "\t-nocorr              do not apply error correction in drive\n");
249 #endif
250         fprintf(stderr, "\t-notrunc     do not truncate outputfile in read mode\n");
251         fprintf(stderr, "\tretries=#    set retry count (default is %d)\n", retries);
252         fprintf(stderr, "\t-overhead    meter SCSI command overhead times\n");
253         fprintf(stderr, "\tmeshpoints=# print read-speed at # locations\n");
254         fprintf(stderr, "\t-factor              try to use speed factor with meshpoints=# if possible\n");
255         fprintf(stderr, "\n");
256         fprintf(stderr, "sectors=0-0 will read nothing, sectors=0-1 will read one sector starting from 0\n");
257         exit(ret);
258 }       
259
260 /* CSTYLED */
261 char    opts[]   = "debug#,d+,kdebug#,kd#,timeout#,quiet,q,verbose+,v+,Verbose+,V+,x+,xd#,silent,s,help,h,version,scanbus,dev*,sectors*,w,c2scan,fulltoc,clone,noerror,nocorr,notrunc,retries#,factor,f*,speed#,ts&,overhead,meshpoints#";
262
263 int
264 main(int argc, char *argv[])
265 {
266         char    *dev = NULL;
267         int     fcount;
268         int     cac;
269         char    * const *cav;
270         int     scsibus = -1;
271         int     target  = -1;
272         int     lun     = -1;
273         int     silent  = 0;
274         int     verbose = 0;
275         int     kdebug  = 0;
276         int     debug   = 0;
277         int     deftimeout = 40;
278         int     pversion = 0;
279         int     scanbus = 0;
280         int     speed   = -1;
281         int     dooverhead = 0;
282         SCSI    *usalp;
283         char    *filename = NULL;
284         char    *sectors = NULL;
285
286         save_args(argc, argv);
287
288         cac = --argc;
289         cav = ++argv;
290
291         if (getallargs(&cac, &cav, opts,
292                         &debug, &debug,
293                         &kdebug, &kdebug,
294                         &deftimeout,
295                         &quiet, &quiet,
296                         &lverbose, &lverbose,
297                         &verbose, &verbose,
298                         &xdebug, &xdebug,
299                         &silent, &silent,
300                         &help, &help, &pversion,
301                         &scanbus, &dev, &sectors, &do_write,
302                         &c2scan,
303                         &fulltoc, &clonemode,
304                         &noerror, &nocorr,
305                         &notrunc, &retries, &do_factor, &filename,
306                         &speed, getnum, &Sbufsize,
307                         &dooverhead, &meshpoints) < 0) {
308                 errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]);
309                 usage(EX_BAD);
310         }
311         if (help)
312                 usage(0);
313         if (pversion) {
314                 printf("readcd %s is not what you see here. This line is only a fake for too clever\n"
315                                 "GUIs and other frontend applications. In fact, this program is:\n", cdr_version);
316
317                 printf("readom " CDRKIT_VERSION " (" HOST_SYSTEM ")\n"
318                                 "Copyright (C) 1987, 1995-2006 Joerg Schilling\n"
319                                 "Copyright (C) 2006 Cdrkit maintainers\n"
320                                 "(modified version of <censored> -- "
321                                 "don't bother Joerg Schilling with problems)\n");
322                 exit(0);
323         }
324
325         fcount = 0;
326         cac = argc;
327         cav = argv;
328
329         while (getfiles(&cac, &cav, opts) > 0) {
330                 fcount++;
331                 if (fcount == 1) {
332                         if (*astoi(cav[0], &target) != '\0') {
333                                 errmsgno(EX_BAD,
334                                         "Target '%s' is not a Number.\n",
335                                                                 cav[0]);
336                                 usage(EX_BAD);
337                                 /* NOTREACHED */
338                         }
339                 }
340                 if (fcount == 2) {
341                         if (*astoi(cav[0], &lun) != '\0') {
342                                 errmsgno(EX_BAD,
343                                         "Lun is '%s' not a Number.\n",
344                                                                 cav[0]);
345                                 usage(EX_BAD);
346                                 /* NOTREACHED */
347                         }
348                 }
349                 if (fcount == 3) {
350                         if (*astoi(cav[0], &scsibus) != '\0') {
351                                 errmsgno(EX_BAD,
352                                         "Scsibus is '%s' not a Number.\n",
353                                                                 cav[0]);
354                                 usage(EX_BAD);
355                                 /* NOTREACHED */
356                         }
357                 }
358                 cac--;
359                 cav++;
360         }
361 /*fprintf(stderr, "dev: '%s'\n", dev);*/
362         if (!scanbus)
363                 cdr_defaults(&dev, NULL, NULL, NULL);
364         if (debug) {
365                 printf("dev: '%s'\n", dev);
366         }
367         if (!scanbus && dev == NULL &&
368             scsibus == -1 && (target == -1 || lun == -1)) {
369                 errmsgno(EX_BAD, "No SCSI device specified.\n");
370                 usage(EX_BAD);
371         }
372         if (dev || scanbus) {
373                 char    errstr[80];
374
375                 /*
376                  * Call usal_remote() to force loading the remote SCSI transport
377                  * library code that is located in librusal instead of the dummy
378                  * remote routines that are located inside libusal.
379                  */
380                 usal_remote();
381                 if (dev != NULL &&
382                     ((strncmp(dev, "HELP", 4) == 0) ||
383                     (strncmp(dev, "help", 4) == 0))) {
384                         usal_help(stderr);
385                         exit(0);
386                 }
387                 if ((usalp = usal_open(dev, errstr, sizeof (errstr), debug, lverbose)) == (SCSI *)0) {
388                         int     err = geterrno();
389
390                         errmsgno(err, "%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":"");
391                         errmsgno(EX_BAD, "For possible targets try 'wodim -scanbus'.%s\n",
392                                                 geteuid() ? " Make sure you are root.":"");
393                         errmsgno(EX_BAD, "For possible transport specifiers try 'wodim dev=help'.\n");
394                         exit(err);
395                 }
396         } else {
397                 if (scsibus == -1 && target >= 0 && lun >= 0)
398                         scsibus = 0;
399
400                 usalp = usal_smalloc();
401                 usalp->debug = debug;
402                 usalp->kdebug = kdebug;
403
404                 usal_settarget(usalp, scsibus, target, lun);
405                 if (usal__open(usalp, NULL) <= 0)
406                         comerr("Cannot open SCSI driver.\n");
407         }
408         usalp->silent = silent;
409         usalp->verbose = verbose;
410         usalp->debug = debug;
411         usalp->kdebug = kdebug;
412         usal_settimeout(usalp, deftimeout);
413
414         if (Sbufsize == 0)
415                 Sbufsize = 256*1024L;
416         Sbufsize = usal_bufsize(usalp, Sbufsize);
417         if ((Sbuf = usal_getbuf(usalp, Sbufsize)) == NULL)
418                 comerr("Cannot get SCSI I/O buffer.\n");
419
420 #ifdef  HAVE_PRIV_SET
421         is_suid = priv_ineffect(PRIV_FILE_DAC_READ) &&
422                     !priv_ineffect(PRIV_PROC_SETID);
423         /*
424          * Give up privs we do not need anymore.
425          * We no longer need:
426          *      file_dac_read,net_privaddr
427          * We still need:
428          *      sys_devices
429          */
430         priv_set(PRIV_OFF, PRIV_EFFECTIVE,
431                 PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL);
432         priv_set(PRIV_OFF, PRIV_PERMITTED,
433                 PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL);
434         priv_set(PRIV_OFF, PRIV_INHERITABLE,
435                 PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL);
436 #endif
437         /*
438          * This is only for OS that do not support fine grained privs.
439          */
440         if (!is_suid)
441                 is_suid = geteuid() != getuid();
442         /*
443          * We don't need root privilleges anymore.
444          */
445 #ifdef  HAVE_SETREUID
446         if (setreuid(-1, getuid()) < 0)
447 #else
448 #ifdef  HAVE_SETEUID
449         if (seteuid(getuid()) < 0)
450 #else
451         if (setuid(getuid()) < 0)
452 #endif
453 #endif
454                 comerr("Panic cannot set back effective uid.\n");
455
456         /* code to use SCG */
457
458         if (scanbus) {
459                 select_target(usalp, stdout);
460                 exit(0);
461         }
462         do_inquiry(usalp, FALSE);
463         allow_atapi(usalp, TRUE);    /* Try to switch to 10 byte mode cmds */
464         if (is_mmc(usalp, NULL, NULL)) {
465                 int     rspeed;
466                 int     wspeed;
467                 /*
468                  * At this point we know that we have a SCSI-3/mmc compliant drive.
469                  * Unfortunately ATAPI drives violate the SCSI spec in returning
470                  * a response data format of '1' which from the SCSI spec would
471                  * tell us not to use the "PF" bit in mode select. As ATAPI drives
472                  * require the "PF" bit to be set, we 'correct' the inquiry data.
473                  */
474                 if (usalp->inq->data_format < 2)
475                         usalp->inq->data_format = 2;
476
477                 if ((rspeed = get_curprofile(usalp)) >= 0) {
478                         if (rspeed >= 0x08 && rspeed < 0x10)
479                                 is_cdrom = TRUE;
480                         if (rspeed >= 0x10 && rspeed < 0x20)
481                                 is_dvd = TRUE;
482                 } else {
483                         BOOL    dvd;
484
485                         mmc_check(usalp, NULL, NULL, NULL, NULL, &dvd, NULL);
486                         if (dvd == FALSE) {
487                                 is_cdrom = TRUE;
488                         } else {
489                                 char    xb[32];
490
491                                 if (read_dvd_structure(usalp, (caddr_t)xb, 32, 0, 0, 0) >= 0) {
492                                 /*
493                                  * If read DVD structure is supported and works, then
494                                  * we must have a DVD media in the drive. Signal to
495                                  * use the DVD driver.
496                                  */
497                                         is_dvd = TRUE;
498                                 } else {
499                                         is_cdrom = TRUE;
500                                 }
501                         }
502                 }
503
504                 if (speed > 0)
505                         speed *= 177;
506                 if (speed > 0xFFFF || speed < 0)
507                         speed = 0xFFFF;
508                 scsi_set_speed(usalp, speed, speed, ROTCTL_CLV);
509                 if (scsi_get_speed(usalp, &rspeed, &wspeed) >= 0) {
510                         fprintf(stderr, "Read  speed: %5d kB/s (CD %3dx, DVD %2dx).\n",
511                                 rspeed, rspeed/176, rspeed/1385);
512                         fprintf(stderr, "Write speed: %5d kB/s (CD %3dx, DVD %2dx).\n",
513                                 wspeed, wspeed/176, wspeed/1385);
514                 }
515         }
516         exargs.usalp       = usalp;
517         exargs.old_secsize = -1;
518 /*      exargs.flags       = flags;*/
519         exargs.oerr[2]     = 0;
520
521         /*
522          * Install exit handler before we change the drive status.
523          */
524         on_comerr(exscsi, &exargs);
525         signal(SIGINT, intr);
526         signal(SIGTERM, intr);
527
528         if (dooverhead) {
529                 ovtime(usalp);
530                 comexit(0);
531         }
532
533         if (is_suid) {
534                 if (usalp->inq->type != INQ_ROMD)
535                         comerrno(EX_BAD, "Not root. Will only work on CD-ROM in suid/priv mode\n");
536         }
537
538         if (filename || sectors || c2scan || meshpoints || fulltoc || clonemode) {
539                 dorw(usalp, filename, sectors);
540         } else {
541                 doit(usalp);
542         }
543         comexit(0);
544         return (0);
545 }
546
547 /*
548  * XXX Leider kann man vim Signalhandler keine SCSI Kommandos verschicken
549  * XXX da meistens das letzte SCSI Kommando noch laeuft.
550  * XXX Eine Loesung waere ein Abort Callback in SCSI *.
551  */
552 static void
553 intr(int sig)
554 {
555         didintr++;
556         exsig = sig;
557 /*      comexit(sig);*/
558 }
559
560 /* ARGSUSED */
561 static void
562 exscsi(int excode, void *arg)
563 {
564         struct exargs   *exp = (struct exargs *)arg;
565                 int     i;
566
567         /*
568          * Try to restore the old sector size.
569          */
570         if (exp != NULL && exp->exflags == 0) {
571                 for (i = 0; i < 10*100; i++) {
572                         if (!exp->usalp->running)
573                                 break;
574                         if (i == 10) {
575                                 errmsgno(EX_BAD,
576                                         "Waiting for current SCSI command to finish.\n");
577                         }
578                         usleep(100000);
579                 }
580
581                 if (!exp->usalp->running) {
582                         if (exp->oerr[2] != 0) {
583                                 domode(exp->usalp, exp->oerr[0], exp->oerr[1]);
584                         }
585                         if (exp->old_secsize > 0 && exp->old_secsize != 2048)
586                                 select_secsize(exp->usalp, exp->old_secsize);
587                 }
588                 exp->exflags++; /* Make sure that it only get called once */
589         }
590 }
591
592 static void
593 excdr(int excode, void *arg)
594 {
595         exscsi(excode, arg);
596
597 #ifdef  needed
598         /* Do several other restores/statistics here (see cdrecord.c) */
599 #endif
600 }
601
602 /*
603  * Return milliseconds since start time.
604  */
605 static int
606 prstats(void)
607 {
608         int     sec;
609         int     usec;
610         int     tmsec;
611
612         if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
613                 comerr("Cannot get time\n");
614
615         sec = stoptime.tv_sec - starttime.tv_sec;
616         usec = stoptime.tv_usec - starttime.tv_usec;
617         tmsec = sec*1000 + usec/1000;
618 #ifdef  lint
619         tmsec = tmsec;  /* Bisz spaeter */
620 #endif
621         if (usec < 0) {
622                 sec--;
623                 usec += 1000000;
624         }
625
626         fprintf(stderr, "Time total: %d.%03dsec\n", sec, usec/1000);
627         return (1000*sec + (usec / 1000));
628 }
629
630 /*
631  * Return milliseconds since start time, but be silent this time.
632  */
633 static int
634 prstats_silent(void)
635 {
636         int     sec;
637         int     usec;
638         int     tmsec;
639
640         if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
641                 comerr("Cannot get time\n");
642
643         sec = stoptime.tv_sec - starttime.tv_sec;
644         usec = stoptime.tv_usec - starttime.tv_usec;
645         tmsec = sec*1000 + usec/1000;
646 #ifdef  lint
647         tmsec = tmsec;  /* Bisz spaeter */
648 #endif
649         if (usec < 0) {
650                 sec--;
651                 usec += 1000000;
652         }
653
654         return (1000*sec + (usec / 1000));
655 }
656
657 static void
658 dorw(SCSI *usalp, char *filename, char *sectors)
659 {
660         parm_t  params;
661         char    *p = NULL;
662
663         params.start = 0;
664         params.end = -1;
665         params.sptr = -1;
666         params.askrange = FALSE;
667         params.name = NULL;
668
669         if (filename)
670                 params.name = filename;
671         if (meshpoints > 0) {
672                 if (params.name == NULL)
673                         params.name = "/dev/null";
674         }
675         if (sectors)
676                 p = astol(sectors, &params.start);
677         if (p && *p == '-')
678                 p = astol(++p, &params.end);
679         if (p && *p != '\0')
680                 comerrno(EX_BAD, "Not a valid sector range '%s'\n", sectors);
681
682         if (!wait_unit_ready(usalp, 60))
683                 comerrno(EX_BAD, "Device not ready.\n");
684
685 #ifdef  CLONE_WRITE
686         if (fulltoc) {
687                 if (params.name == NULL)
688                         params.name = "/dev/null";
689                 read_ftoc(usalp, &params, FALSE);
690         } else if (clonemode) {
691                 if (!is_mmc(usalp, NULL, NULL))
692                         comerrno(EX_BAD, "Unsupported device for clone mode.\n");
693                 noerror = TRUE;
694                 if (retries == MAX_RETRY)
695                         retries = 10;
696                 if (params.name == NULL)
697                         params.name = "/dev/null";
698
699                 if (read_ftoc(usalp, &params, TRUE) < 0)
700                         comerrno(EX_BAD, "Read fulltoc problems.\n");
701                 readcd_disk(usalp, &params);
702         } else
703 #endif
704         if (c2scan) {
705                 noerror = TRUE;
706                 if (retries == MAX_RETRY)
707                         retries = 10;
708                 if (params.name == NULL)
709                         params.name = "/dev/null";
710                 readc2_disk(usalp, &params);
711         } else if (do_write)
712                 write_disk(usalp, &params);
713         else
714                 read_disk(usalp, &params);
715 }
716
717 static void
718 doit(SCSI *usalp)
719 {
720         int     i = 0;
721         parm_t  params;
722
723         params.start = 0;
724         params.end = -1;
725         params.sptr = -1;
726         params.askrange = TRUE;
727         params.name = "/dev/null";
728
729         for (;;) {
730                 if (!wait_unit_ready(usalp, 60))
731                         comerrno(EX_BAD, "Device not ready.\n");
732
733                 printf("0:read 1:veri   2:erase   3:read buffer 4:cache 5:ovtime 6:cap\n");
734                 printf("7:wne  8:floppy 9:verify 10:checkcmds  11:read disk 12:write disk\n");
735                 printf("13:scsireset 14:seektest 15: readda 16: reada 17: c2err\n");
736 #ifdef  CLONE_WRITE
737                 printf("18:readom 19: lin 20: full toc\n");
738 #endif
739
740                 getint("Enter selection:", &i, 0, 20);
741                 if (didintr)
742                         return;
743
744                 switch (i) {
745
746                 case 5:         ovtime(usalp);          break;
747                 case 11:        read_disk(usalp, 0);    break;
748                 case 12:        write_disk(usalp, 0);   break;
749                 case 15:        ra(usalp);              break;
750 /*              case 16:        reada_disk(usalp, 0, 0);        break;*/
751                 case 17:        readc2_disk(usalp, &params);    break;
752 #ifdef  CLONE_WRITE
753                 case 18:        readcd_disk(usalp, 0);  break;
754                 case 19:        read_lin(usalp, 0);     break;
755                 case 20:        read_ftoc(usalp, 0, FALSE);     break;
756 #endif
757                 }
758         }
759 }
760
761 static void
762 read_disk(SCSI *usalp, parm_t *parmp)
763 {
764         rparm_t rp;
765
766         read_capacity(usalp);
767         print_capacity(usalp, stderr);
768
769         rp.errors = 0;
770         rp.c2_errors = 0;
771         rp.c2_maxerrs = 0;
772         rp.c2_errsecs = 0;
773         rp.c2_badsecs = 0;
774         rp.secsize = usalp->cap->c_bsize;
775
776         read_generic(usalp, parmp, fread_data, &rp, fdata_null);
777 }
778
779 #ifdef  CLONE_WRITE
780 static void
781 readcd_disk(SCSI *usalp, parm_t *parmp)
782 {
783         rparm_t rp;
784         int     osecsize = 2048;
785         int     oerr = 0;
786         int     oretr = 10;
787         int     (*funcp)(SCSI *_usalp, rparm_t *_rp, caddr_t bp, long addr, int cnt);
788
789         usalp->silent++;
790         if (read_capacity(usalp) >= 0)
791                 osecsize = usalp->cap->c_bsize;
792         usalp->silent--;
793         if (osecsize != 2048)
794                 select_secsize(usalp, 2048);
795
796         read_capacity(usalp);
797         print_capacity(usalp, stderr);
798
799         rp.errors = 0;
800         rp.c2_errors = 0;
801         rp.c2_maxerrs = 0;
802         rp.c2_errsecs = 0;
803         rp.c2_badsecs = 0;
804         rp.secsize = 2448;
805         rp.ismmc = is_mmc(usalp, NULL, NULL);
806         funcp = fread_2448;
807
808         wait_unit_ready(usalp, 10);
809         if (fread_2448(usalp, &rp, Sbuf, 0, 0) < 0) {
810                 errmsgno(EX_BAD, "read 2448 failed\n");
811                 if (rp.ismmc &&
812                     fread_2448_16(usalp, &rp, Sbuf, 0, 0) >= 0) {
813                         errmsgno(EX_BAD, "read 2448_16 : OK\n");
814
815                         funcp = fread_2448_16;
816                 }
817         }
818
819         oldmode(usalp, &oerr, &oretr);
820         exargs.oerr[0] = oerr;
821         exargs.oerr[1] = oretr;
822         exargs.oerr[2] = 0xFF;
823         if (parmp == NULL)              /* XXX Nur am Anfang!!! */
824                 domode(usalp, -1, -1);
825         else
826                 domode(usalp, nocorr?0x21:0x20, 10);
827
828         read_generic(usalp, parmp, funcp, &rp, fdata_null);
829         if (osecsize != 2048)
830                 select_secsize(usalp, osecsize);
831         domode(usalp, oerr, oretr);
832 }
833
834 /* ARGSUSED */
835 static void
836 read_lin(SCSI *usalp, parm_t *parmp)
837 {
838         parm_t  parm;
839         rparm_t rp;
840
841         read_capacity(usalp);
842         print_capacity(usalp, stderr);
843
844         parm.start = ULONG_C(0xF0000000);
845         parm.end =   ULONG_C(0xFF000000);
846         parm.name = "DDD";
847
848         rp.errors = 0;
849         rp.c2_errors = 0;
850         rp.c2_maxerrs = 0;
851         rp.c2_errsecs = 0;
852         rp.c2_badsecs = 0;
853         rp.secsize = 2448;
854         rp.ismmc = is_mmc(usalp, NULL, NULL);
855         domode(usalp, -1, -1);
856         read_generic(usalp, &parm, fread_lin, &rp, fdata_null);
857 }
858
859 static int
860 read_secheader(SCSI *usalp, long addr)
861 {
862         rparm_t rp;
863         int     osecsize = 2048;
864         int     ret = 0;
865
866         usalp->silent++;
867         if (read_capacity(usalp) >= 0)
868                 osecsize = usalp->cap->c_bsize;
869         usalp->silent--;
870         if (osecsize != 2048)
871                 select_secsize(usalp, 2048);
872
873         read_capacity(usalp);
874
875         rp.errors = 0;
876         rp.c2_errors = 0;
877         rp.c2_maxerrs = 0;
878         rp.c2_errsecs = 0;
879         rp.c2_badsecs = 0;
880         rp.secsize = 2352;
881         rp.ismmc = is_mmc(usalp, NULL, NULL);
882
883         wait_unit_ready(usalp, 10);
884
885         fillbytes(Sbuf, 2352, '\0');
886         if (fread_2352(usalp, &rp, Sbuf, addr, 1) < 0) {
887                 ret = -1;
888         }
889         if (osecsize != 2048)
890                 select_secsize(usalp, osecsize);
891         return (ret);
892 }
893
894 /* ARGSUSED */
895 static int
896 read_ftoc(SCSI *usalp, parm_t *parmp, BOOL do_sectype)
897 {
898         FILE    *f;
899         int     i;
900         char    filename[1024];
901         struct  tocheader *tp;
902         char    *p;
903         char    xb[256];
904         int     len;
905         char    xxb[10000];
906
907
908         strcpy(filename, "toc.dat");
909         if (strcmp(parmp->name, "/dev/null") != 0) {
910
911                 len = strlen(parmp->name);
912                 if (len > (sizeof (filename)-5)) {
913                         len = sizeof (filename)-5;
914                 }
915                 snprintf(filename, sizeof (filename), "%.*s.toc", len, parmp->name);
916         }
917
918         tp = (struct tocheader *)xb;
919
920         fillbytes((caddr_t)xb, sizeof (xb), '\0');
921         if (read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_FULLTOC) < 0) {
922                 if (usalp->silent == 0 || usalp->verbose > 0)
923                         errmsgno(EX_BAD, "Cannot read TOC header\n");
924                 return (-1);
925         }
926         len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
927         fprintf(stderr, "TOC len: %d. First Session: %d Last Session: %d.\n", len, tp->first, tp->last);
928
929         if (read_toc(usalp, xxb, 0, len, 0, FMT_FULLTOC) < 0) {
930                 if (len & 1) {
931                         /*
932                          * Work around a bug in some operating systems that do not
933                          * handle odd byte DMA correctly for ATAPI drives.
934                          */
935                         wait_unit_ready(usalp, 30);
936                         read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_FULLTOC);
937                         wait_unit_ready(usalp, 30);
938                         if (read_toc(usalp, xxb, 0, len+1, 0, FMT_FULLTOC) >= 0) {
939                                 goto itworked;
940                         }
941                 }
942                 if (usalp->silent == 0)
943                         errmsgno(EX_BAD, "Cannot read full TOC\n");
944                 return (-1);
945         }
946
947 itworked:
948         f = fileopen(filename, "wctb");
949
950         if (f == NULL)
951                 comerr("Cannot open '%s'.\n", filename);
952         filewrite(f, xxb, len);
953         if (do_sectype)
954                 read_sectypes(usalp, f);
955         fflush(f);
956         fclose(f);
957
958         p = &xxb[4];
959         for (; p < &xxb[len]; p += 11) {
960                 for (i = 0; i < 11; i++)
961                         fprintf(stderr, "%02X ", p[i] & 0xFF);
962                 fprintf(stderr, "\n");
963         }
964         /*
965          * List all lead out start times to give information about multi
966          * session disks.
967          */
968         p = &xxb[4];
969         for (; p < &xxb[len]; p += 11) {
970                 if ((p[3] & 0xFF) == 0xA2) {
971                         fprintf(stderr, "Lead out %d: %ld\n", p[0], msf_to_lba(p[8], p[9], p[10], TRUE));
972                 }
973         }
974         return (0);
975 }
976
977 static void
978 read_sectypes(SCSI *usalp, FILE *f)
979 {
980         char    sect;
981
982         sect = SECT_AUDIO;
983         get_sectype(usalp, 4, &sect);
984         if (f != NULL)
985                 filewrite(f, &sect, 1);
986         if (xdebug)
987                 usal_prbytes("sec 0", (Uchar *)Sbuf, 16);
988
989         sect = SECT_AUDIO;
990         get_sectype(usalp, usalp->cap->c_baddr-4, &sect);
991         if (f != NULL)
992                 filewrite(f, &sect, 1);
993         if (xdebug) {
994                 usal_prbytes("sec E", (Uchar *)Sbuf, 16);
995                 fprintf(stderr, "baddr: %ld\n", (long)usalp->cap->c_baddr);
996         }
997 }
998
999 static void
1000 get_sectype(SCSI *usalp, long addr, char *st)
1001 {
1002         char    *synchdr = "\0\377\377\377\377\377\377\377\377\377\377\0";
1003         int     sectype = SECT_AUDIO;
1004         int     i;
1005         long    raddr = addr;
1006 #define _MAX_TRY_       20
1007
1008         usalp->silent++;
1009         for (i = 0; i < _MAX_TRY_ && read_secheader(usalp, raddr) < 0; i++) {
1010                 if (addr == 0)
1011                         raddr++;
1012                 else
1013                         raddr--;
1014         }
1015         usalp->silent--;
1016         if (i >= _MAX_TRY_) {
1017                 fprintf(stderr, "Sectype (%ld) is CANNOT\n", addr);
1018                 return;
1019         } else if (i > 0) {
1020                 fprintf(stderr, "Sectype (%ld) needed %d retries\n", addr, i);
1021         }
1022 #undef  _MAX_TRY_
1023
1024         if (cmpbytes(Sbuf, synchdr, 12) < 12) {
1025                 if (xdebug)
1026                         fprintf(stderr, "Sectype (%ld) is AUDIO\n", addr);
1027                 if (st)
1028                         *st = SECT_AUDIO;
1029                 return;
1030         }
1031         if (xdebug)
1032                 fprintf(stderr, "Sectype (%ld) is DATA\n", addr);
1033         if (Sbuf[15] == 0) {
1034                 if (xdebug)
1035                         fprintf(stderr, "Sectype (%ld) is MODE 0\n", addr);
1036                 sectype = SECT_MODE_0;
1037
1038         } else if (Sbuf[15] == 1) {
1039                 if (xdebug)
1040                         fprintf(stderr, "Sectype (%ld) is MODE 1\n", addr);
1041                 sectype = SECT_ROM;
1042
1043         } else if (Sbuf[15] == 2) {
1044                 if (xdebug)
1045                         fprintf(stderr, "Sectype (%ld) is MODE 2\n", addr);
1046
1047                 if ((Sbuf[16+2]  & 0x20) == 0 &&
1048                     (Sbuf[16+4+2]  & 0x20) == 0) {
1049                         if (xdebug)
1050                                 fprintf(stderr, "Sectype (%ld) is MODE 2 form 1\n", addr);
1051                         sectype = SECT_MODE_2_F1;
1052
1053                 } else if ((Sbuf[16+2]  & 0x20) != 0 &&
1054                     (Sbuf[16+4+2]  & 0x20) != 0) {
1055                         if (xdebug)
1056                                 fprintf(stderr, "Sectype (%ld) is MODE 2 form 2\n", addr);
1057                         sectype = SECT_MODE_2_F2;
1058                 } else {
1059                         if (xdebug)
1060                                 fprintf(stderr, "Sectype (%ld) is MODE 2 formless\n", addr);
1061                         sectype = SECT_MODE_2;
1062                 }
1063         } else {
1064                 fprintf(stderr, "Sectype (%ld) is UNKNOWN\n", addr);
1065         }
1066         if (st)
1067                 *st = sectype;
1068         if (xdebug)
1069                 fprintf(stderr, "Sectype (%ld) is 0x%02X\n", addr, sectype);
1070 }
1071
1072 #endif  /* CLONE_WRITE */
1073
1074 char    zeroblk[512];
1075
1076 static void
1077 readc2_disk(SCSI *usalp, parm_t *parmp)
1078 {
1079         rparm_t rp;
1080         int     osecsize = 2048;
1081         int     oerr = 0;
1082         int     oretr = 10;
1083
1084         usalp->silent++;
1085         if (read_capacity(usalp) >= 0)
1086                 osecsize = usalp->cap->c_bsize;
1087         usalp->silent--;
1088         if (osecsize != 2048)
1089                 select_secsize(usalp, 2048);
1090
1091         read_capacity(usalp);
1092         print_capacity(usalp, stderr);
1093
1094         rp.errors = 0;
1095         rp.c2_errors = 0;
1096         rp.c2_maxerrs = 0;
1097         rp.c2_errsecs = 0;
1098         rp.c2_badsecs = 0;
1099         rp.secsize = 2352 + 294;
1100         rp.ismmc = is_mmc(usalp, NULL, NULL);
1101
1102         oldmode(usalp, &oerr, &oretr);
1103         exargs.oerr[0] = oerr;
1104         exargs.oerr[1] = oretr;
1105         exargs.oerr[2] = 0xFF;
1106         domode(usalp, 0x21, 10);
1107
1108
1109         read_generic(usalp, parmp, fread_c2, &rp, fdata_c2);
1110         if (osecsize != 2048)
1111                 select_secsize(usalp, osecsize);
1112         domode(usalp, oerr, oretr);
1113
1114         printf("Total of %d hard read errors.\n", rp.errors);
1115         printf("C2 errors total: %d bytes in %d sectors on disk\n", rp.c2_errors, rp.c2_errsecs);
1116         printf("C2 errors rate: %f%% \n", (100.0*rp.c2_errors)/usalp->cap->c_baddr/2352);
1117         printf("C2 errors on worst sector: %d, sectors with 100+ C2 errors: %d\n", rp.c2_maxerrs, rp.c2_badsecs);
1118 }
1119
1120 /* ARGSUSED */
1121 static int
1122 fread_data(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt)
1123 {
1124         return (read_g1(usalp, bp, addr, cnt));
1125 }
1126
1127 #ifdef  CLONE_WRITE
1128 static int
1129 fread_2448(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt)
1130 {
1131         if (rp->ismmc) {
1132                 return (read_cd(usalp, bp, addr, cnt, rp->secsize,
1133                         /* Sync + all headers + user data + EDC/ECC */
1134                         (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1135                         /* plus all subchannels RAW */
1136                         1));
1137         } else {
1138                 return (read_da(usalp, bp, addr, cnt, rp->secsize,
1139                         /* Sync + all headers + user data + EDC/ECC + all subch */
1140                         0x02));
1141         }
1142 }
1143
1144 static int
1145 fread_2448_16(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt)
1146 {
1147
1148         if (rp->ismmc) {
1149                 track_t trackdesc;
1150                 int     ret;
1151                 int     i;
1152                 char    *p;
1153
1154                 trackdesc.isecsize = 2368;
1155                 trackdesc.secsize = 2448;
1156                 ret = read_cd(usalp, bp, addr, cnt, 2368,
1157                         /* Sync + all headers + user data + EDC/ECC */
1158                         (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1159                         /* subchannels P/Q */
1160                         2);
1161                 if (ret < 0)
1162                         return (ret);
1163
1164                 scatter_secs(&trackdesc, bp, cnt);
1165                 for (i = 0, p = bp+2352; i < cnt; i++) {
1166 #ifdef  more_than_q_sub
1167                         if ((p[15] & 0x80) != 0)
1168                                 printf("P");
1169 #endif
1170                         /*
1171                          * As the drives don't return P-sub, we check
1172                          * whether the index equals 0.
1173                          */
1174                         qpto96((Uchar *)p, (Uchar *)p, p[2] == 0);
1175                         p += 2448;
1176                 }
1177                 return (ret);
1178         } else {
1179                 comerrno(EX_BAD, "Cannot fread_2448_16 on non MMC drives\n");
1180
1181                 return (read_da(usalp, bp, addr, cnt, rp->secsize,
1182                         /* Sync + all headers + user data + EDC/ECC + all subch */
1183                         0x02));
1184         }
1185 }
1186
1187 static int
1188 fread_2352(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt)
1189 {
1190         if (rp->ismmc) {
1191                 return (read_cd(usalp, bp, addr, cnt, rp->secsize,
1192                         /* Sync + all headers + user data + EDC/ECC */
1193                         (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1194                         /* NO subchannels */
1195                         0));
1196         } else {
1197                 comerrno(EX_BAD, "Cannot fread_2352 on non MMC drives\n");
1198
1199                 return (read_da(usalp, bp, addr, cnt, rp->secsize,
1200                         /* Sync + all headers + user data + EDC/ECC + all subch */
1201                         0x02));
1202         }
1203 }
1204
1205 static int
1206 fread_lin(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt)
1207 {
1208         if (addr != ULONG_C(0xF0000000))
1209                 addr = ULONG_C(0xFFFFFFFF);
1210
1211         return (read_cd(usalp, bp, addr, cnt, rp->secsize,
1212                 /* Sync + all headers + user data + EDC/ECC */
1213                 (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1214                 /* plus all subchannels RAW */
1215                 1));
1216 }
1217 #endif  /* CLONE_WRITE */
1218
1219 static int
1220 bits(int c)
1221 {
1222         int     n = 0;
1223
1224         if (c & 0x01)
1225                 n++;
1226         if (c & 0x02)
1227                 n++;
1228         if (c & 0x04)
1229                 n++;
1230         if (c & 0x08)
1231                 n++;
1232         if (c & 0x10)
1233                 n++;
1234         if (c & 0x20)
1235                 n++;
1236         if (c & 0x40)
1237                 n++;
1238         if (c & 0x80)
1239                 n++;
1240         return (n);
1241 }
1242
1243 static int
1244 bitidx(int c)
1245 {
1246         if (c & 0x80)
1247                 return (0);
1248         if (c & 0x40)
1249                 return (1);
1250         if (c & 0x20)
1251                 return (2);
1252         if (c & 0x10)
1253                 return (3);
1254         if (c & 0x08)
1255                 return (4);
1256         if (c & 0x04)
1257                 return (5);
1258         if (c & 0x02)
1259                 return (6);
1260         if (c & 0x01)
1261                 return (7);
1262         return (-1);
1263 }
1264
1265 static int
1266 fread_c2(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt)
1267 {
1268         if (rp->ismmc) {
1269                 return (read_cd(usalp, bp, addr, cnt, rp->secsize,
1270                         /* Sync + all headers + user data + EDC/ECC + C2 */
1271 /*                      (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 2 << 1),*/
1272                         (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 1 << 1),
1273                         /* without subchannels */
1274                         0));
1275         } else {
1276                 return (read_da(usalp, bp, addr, cnt, rp->secsize,
1277                         /* Sync + all headers + user data + EDC/ECC + C2 */
1278                         0x04));
1279         }
1280 }
1281
1282 /* ARGSUSED */
1283 static int
1284 fdata_null(rparm_t *rp, caddr_t bp, long addr, int cnt)
1285 {
1286         return (0);
1287 }
1288
1289 static int
1290 fdata_c2(rparm_t *rp, caddr_t bp, long addr, int cnt)
1291 {
1292         int     i;
1293         int     j;
1294         int     k;
1295         char    *p;
1296
1297         p = &bp[2352];
1298
1299         for (i = 0; i < cnt; i++, p += (2352+294)) {
1300 /*              usal_prbytes("XXX ", p, 294);*/
1301                 if ((j = cmpbytes(p, zeroblk, 294)) < 294) {
1302                         printf("C2 in sector: %3ld first at byte: %4d (0x%02X)", addr+i,
1303                                 j*8 + bitidx(p[j]), p[j]&0xFF);
1304                         for (j = 0, k = 0; j < 294; j++)
1305                                 k += bits(p[j]);
1306                         printf(" total: %4d errors\n", k);
1307 /*                      usal_prbytes("XXX ", p, 294);*/
1308                         rp->c2_errors += k;
1309                         if (k > rp->c2_maxerrs)
1310                                 rp->c2_maxerrs = k;
1311                         rp->c2_errsecs++;
1312                         if (k >= 100)
1313                                 rp->c2_badsecs += 1;
1314                 }
1315         }
1316         return (0);
1317 }
1318
1319 #ifdef  used
1320 static int
1321 read_scsi_g1(SCSI *usalp, caddr_t bp, long addr, int cnt)
1322 {
1323         register struct usal_cmd        *scmd = usalp->scmd;
1324
1325         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1326         scmd->addr = bp;
1327 /*      scmd->size = cnt*512;*/
1328         scmd->size = cnt*usalp->cap->c_bsize;
1329         scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1330         scmd->cdb_len = SC_G1_CDBLEN;
1331         scmd->sense_len = CCS_SENSE_LEN;
1332         scmd->cdb.g1_cdb.cmd = 0x28;
1333         scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1334         g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
1335         g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1336
1337         usalp->cmdname = "read extended";
1338
1339         return (usal_cmd(usalp));
1340 }
1341 #endif
1342
1343 #define G0_MAXADDR      0x1FFFFFL
1344
1345 int
1346 write_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt)
1347 {
1348         if (addr <= G0_MAXADDR)
1349                 return (write_g0(usalp, bp, addr, cnt));
1350         else
1351                 return (write_g1(usalp, bp, addr, cnt));
1352 }
1353
1354 int
1355 write_g0(SCSI *usalp, caddr_t bp, long addr, int cnt)
1356 {
1357         register struct usal_cmd        *scmd = usalp->scmd;
1358
1359         if (usalp->cap->c_bsize <= 0)
1360                 raisecond("capacity_not_set", 0L);
1361
1362         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1363         scmd->addr = bp;
1364         scmd->size = cnt*usalp->cap->c_bsize;
1365         scmd->flags = SCG_DISRE_ENA;
1366         scmd->cdb_len = SC_G0_CDBLEN;
1367         scmd->sense_len = CCS_SENSE_LEN;
1368         scmd->cdb.g0_cdb.cmd = SC_WRITE;
1369         scmd->cdb.g0_cdb.lun = usal_lun(usalp);
1370         g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
1371         scmd->cdb.g0_cdb.count = (Uchar)cnt;
1372
1373         usalp->cmdname = "write_g0";
1374
1375         return (usal_cmd(usalp));
1376 }
1377
1378 int
1379 write_g1(SCSI *usalp, caddr_t bp, long addr, int cnt)
1380 {
1381         register struct usal_cmd        *scmd = usalp->scmd;
1382
1383         if (usalp->cap->c_bsize <= 0)
1384                 raisecond("capacity_not_set", 0L);
1385
1386         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1387         scmd->addr = bp;
1388         scmd->size = cnt*usalp->cap->c_bsize;
1389         scmd->flags = SCG_DISRE_ENA;
1390         scmd->cdb_len = SC_G1_CDBLEN;
1391         scmd->sense_len = CCS_SENSE_LEN;
1392         scmd->cdb.g1_cdb.cmd = SC_EWRITE;
1393         scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1394         g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
1395         g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1396
1397         usalp->cmdname = "write_g1";
1398
1399         return (usal_cmd(usalp));
1400 }
1401
1402 #ifdef  used
1403 static void
1404 Xrequest_sense(SCSI *usalp)
1405 {
1406         char    sense_buf[32];
1407         struct  usal_cmd ocmd;
1408         int     sense_count;
1409         char    *cmdsave;
1410         register struct usal_cmd        *scmd = usalp->scmd;
1411
1412         cmdsave = usalp->cmdname;
1413
1414         movebytes(scmd, &ocmd, sizeof (*scmd));
1415
1416         fillbytes((caddr_t)sense_buf, sizeof (sense_buf), '\0');
1417
1418         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1419         scmd->addr = (caddr_t)sense_buf;
1420         scmd->size = sizeof (sense_buf);
1421         scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1422         scmd->cdb_len = SC_G0_CDBLEN;
1423         scmd->sense_len = CCS_SENSE_LEN;
1424         scmd->cdb.g1_cdb.cmd = 0x3;
1425         scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1426         scmd->cdb.g0_cdb.count = sizeof (sense_buf);
1427
1428         usalp->cmdname = "request sense";
1429
1430         usal_cmd(usalp);
1431
1432         sense_count = sizeof (sense_buf) - usal_getresid(usalp);
1433         movebytes(&ocmd, scmd, sizeof (*scmd));
1434         scmd->sense_count = sense_count;
1435         movebytes(sense_buf, (Uchar *)&scmd->sense, scmd->sense_count);
1436
1437         usalp->cmdname = cmdsave;
1438         usal_printerr(usalp);
1439         usal_printresult(usalp);        /* XXX restore key/code in future */
1440 }
1441 #endif
1442
1443 static int
1444 read_retry(SCSI *usalp, caddr_t bp, long addr, long cnt, 
1445                           int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt), 
1446                           rparm_t *rp)
1447 {
1448 /*      int     secsize = usalp->cap->c_bsize;*/
1449         int     secsize = rp->secsize;
1450         int     try = 0;
1451         int     err;
1452         char    dummybuf[8192];
1453
1454         if (secsize > sizeof (dummybuf)) {
1455                 errmsgno(EX_BAD, "Cannot retry, sector size %d too big.\n", secsize);
1456                 return (-1);
1457         }
1458
1459         errmsgno(EX_BAD, "Retrying from sector %ld.\n", addr);
1460         while (cnt > 0) {
1461                 fprintf(stderr, ".");
1462
1463                 do {
1464                         if (didintr)
1465                                 comexit(exsig);         /* XXX besseres Konzept?!*/
1466                         wait_unit_ready(usalp, 120);
1467                         if (try >= 10) {                /* First 10 retries without seek */
1468                                 if ((try % 8) == 0) {
1469                                         fprintf(stderr, "+");   /* Read last sector */
1470                                         usalp->silent++;
1471                                         (*rfunc)(usalp, rp, dummybuf, usalp->cap->c_baddr, 1);
1472                                         usalp->silent--;
1473                                 } else if ((try % 4) == 0) {
1474                                         fprintf(stderr, "-");   /* Read first sector */
1475                                         usalp->silent++;
1476                                         (*rfunc)(usalp, rp, dummybuf, 0, 1);
1477                                         usalp->silent--;
1478                                 } else {
1479                                         fprintf(stderr, "~");   /* Read random sector */
1480                                         usalp->silent++;
1481                                         (*rfunc)(usalp, rp, dummybuf, choice(usalp->cap->c_baddr), 1);
1482                                         usalp->silent--;
1483                                 }
1484                                 if (didintr)
1485                                         comexit(exsig);         /* XXX besseres Konzept?!*/
1486                                 wait_unit_ready(usalp, 120);
1487                         }
1488                         if (didintr)
1489                                 comexit(exsig);         /* XXX besseres Konzept?!*/
1490
1491                         fillbytes(bp, secsize, 0);
1492
1493                         usalp->silent++;
1494                         err = (*rfunc)(usalp, rp, bp, addr, 1);
1495                         usalp->silent--;
1496
1497                         if (err < 0) {
1498                                 err = usalp->scmd->ux_errno;
1499 /*                              fprintf(stderr, "\n");*/
1500 /*                              errmsgno(err, "Cannot read source disk\n");*/
1501                         } else {
1502                                 if (usal_getresid(usalp)) {
1503                                         fprintf(stderr, "\nresid: %d\n", usal_getresid(usalp));
1504                                         return (-1);
1505                                 }
1506                                 break;
1507                         }
1508                 } while (++try < retries);
1509
1510                 if (try >= retries) {
1511                         fprintf(stderr, "\n");
1512                         errmsgno(err, "Error on sector %ld not corrected. Total of %d errors.\n",
1513                                         addr, ++rp->errors);
1514
1515                         if (usalp->silent <= 1 && lverbose > 0)
1516                                 usal_printerr(usalp);
1517
1518                         add_bad(addr);
1519
1520                         if (!noerror)
1521                                 return (-1);
1522                         errmsgno(EX_BAD, "-noerror set, continuing ...\n");
1523                 } else {
1524                         if (try >= maxtry)
1525                                 maxtry = try;
1526
1527                         if (try > 1) {
1528                                 fprintf(stderr, "\n");
1529                                 errmsgno(EX_BAD,
1530                                 "Error on sector %ld corrected after %d tries. Total of %d errors.\n",
1531                                         addr, try, rp->errors);
1532                         }
1533                 }
1534                 try = 0;
1535                 cnt -= 1;
1536                 addr += 1;
1537                 bp += secsize;
1538         }
1539         return (0);
1540 }
1541
1542 static void
1543 read_generic(SCSI *usalp, parm_t *parmp, 
1544                                  int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt),
1545                                  rparm_t *rp,
1546                                  int (*dfunc)(rparm_t *rp, caddr_t bp, long addr, int cnt))
1547 {
1548         char    filename[512];
1549         char    *defname = NULL;
1550         FILE    *f;
1551         long    addr = 0L;
1552         long    old_addr = 0L;
1553         long    num;
1554         long    end = 0L;
1555         long    start = 0L;
1556         long    cnt = 0L;
1557         long    next_point = 0L;
1558         long    secs_per_point = 0L;
1559         double  speed;
1560         int     msec;
1561         int     old_msec = 0;
1562         int     err = 0;
1563         BOOL    askrange = FALSE;
1564         BOOL    isrange = FALSE;
1565         int     secsize = rp->secsize;
1566         int     i = 0;
1567
1568         if (is_suid) {
1569                 if (usalp->inq->type != INQ_ROMD)
1570                         comerrno(EX_BAD, "Not root. Will only read from CD in suid/priv mode\n");
1571         }
1572
1573         if (parmp == NULL || parmp->askrange)
1574                 askrange = TRUE;
1575         if (parmp != NULL && !askrange && (parmp->start <= parmp->end))
1576                 isrange = TRUE;
1577
1578         filename[0] = '\0';
1579
1580         usalp->silent++;
1581         if (read_capacity(usalp) >= 0)
1582                 end = usalp->cap->c_baddr + 1;
1583         usalp->silent--;
1584
1585         if ((end <= 0 && isrange) || (askrange && usal_yes("Ignore disk size? ")))
1586                 end = 10000000; /* Hack to read empty (e.g. blank=fast) disks */
1587
1588         if (parmp) {
1589                 if (parmp->name)
1590                         defname = parmp->name;
1591                 if (defname != NULL) {
1592                         fprintf(stderr, "Copy from SCSI (%d,%d,%d) disk to file '%s'\n",
1593                                         usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp),
1594                                         defname);
1595                 }
1596
1597                 addr = start = parmp->start;
1598                 if (parmp->end != -1 && parmp->end < end)
1599                         end = parmp->end;
1600                 cnt = Sbufsize / secsize;
1601         }
1602
1603         if (defname == NULL) {
1604                 defname = "disk.out";
1605                 fprintf(stderr, "Copy from SCSI (%d,%d,%d) disk to file\n",
1606                                         usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
1607                 fprintf(stderr, "Enter filename [%s]: ", defname); flush();
1608                 (void) rols_getline(filename, sizeof (filename));
1609         }
1610
1611         if (askrange) {
1612                 addr = start;
1613                 getlong("Enter starting sector for copy:", &addr, start, end-1);
1614 /*              getlong("Enter starting sector for copy:", &addr, -300, end-1);*/
1615                 start = addr;
1616         }
1617
1618         if (askrange) {
1619                 num = end - addr;
1620                 getlong("Enter number of sectors to copy:", &num, 1L, num);
1621                 end = addr + num;
1622         }
1623
1624         if (askrange) {
1625 /* XXX askcnt */
1626                 cnt = Sbufsize / secsize;
1627                 getlong("Enter number of sectors per copy:", &cnt, 1L, cnt);
1628         }
1629
1630         if (filename[0] == '\0')
1631                 strncpy(filename, defname, sizeof (filename));
1632         filename[sizeof (filename)-1] = '\0';
1633         if (streql(filename, "-")) {
1634                 f = stdout;
1635 #ifdef  NEED_O_BINARY
1636                 setmode(STDOUT_FILENO, O_BINARY);
1637 #endif
1638         } else if ((f = fileopen(filename, notrunc?"wcub":"wctub")) == NULL)
1639                 comerr("Cannot open '%s'.\n", filename);
1640
1641         fprintf(stderr, "end:  %8ld\n", end);
1642         if (gettimeofday(&starttime, (struct timezone *)0) < 0)
1643                 comerr("Cannot get start time\n");
1644
1645         if (meshpoints > 0) {
1646                 if ((end-start) < meshpoints)
1647                         secs_per_point = 1;
1648                 else
1649                         secs_per_point = (end-start) / meshpoints;
1650                 next_point = start + secs_per_point;
1651                 old_addr = start;
1652         }
1653
1654         for (; addr < end; addr += cnt) {
1655                 if (didintr)
1656                         comexit(exsig);         /* XXX besseres Konzept?!*/
1657
1658                 if ((addr + cnt) > end)
1659                         cnt = end - addr;
1660
1661                 if (meshpoints > 0) {
1662                         if (addr > next_point) {
1663
1664                                 msec = prstats_silent();
1665                                 if ((msec - old_msec) == 0)             /* Avoid division by zero */
1666                                         msec = old_msec + 1;
1667                                 speed = ((addr - old_addr)/(1000.0/secsize)) / (0.001*(msec - old_msec));
1668                                 if (do_factor) {
1669                                         if (is_cdrom)
1670                                                 speed /= 176.400;
1671                                         else if (is_dvd)
1672                                                 speed /= 1385.0;
1673                                 }
1674                                 fprintf(stderr, "addr: %8ld cnt: %ld", addr, cnt);
1675                                 printf("%8ld %8.2f\n", addr, speed);
1676                                 fprintf(stderr, "\r");
1677                                 next_point += secs_per_point;
1678                                 old_addr = addr;
1679                                 old_msec = msec;
1680                                 i++;
1681                                 if (meshpoints < 100)
1682                                         flush();
1683                                 else if (i % (meshpoints/100) == 0)
1684                                         flush();
1685                         }
1686                 }
1687                 fprintf(stderr, "addr: %8ld cnt: %ld\r", addr, cnt);
1688
1689                 usalp->silent++;
1690                 if ((*rfunc)(usalp, rp, Sbuf, addr, cnt) < 0) {
1691                         usalp->silent--;
1692                         err = usalp->scmd->ux_errno;
1693                         if (quiet) {
1694                                 fprintf(stderr, "\n");
1695                         } else if (usalp->silent == 0) {
1696                                 usal_printerr(usalp);
1697                         }
1698                         errmsgno(err, "Cannot read source disk\n");
1699
1700                         if (read_retry(usalp, Sbuf, addr, cnt, rfunc, rp) < 0)
1701                                 goto out;
1702                 } else {
1703                         usalp->silent--;
1704                         if (usal_getresid(usalp)) {
1705                                 fprintf(stderr, "\nresid: %d\n", usal_getresid(usalp));
1706                                 goto out;
1707                         }
1708                 }
1709                 (*dfunc)(rp, Sbuf, addr, cnt);
1710                 if (filewrite(f, Sbuf, cnt * secsize) < 0) {
1711                         err = geterrno();
1712                         fprintf(stderr, "\n");
1713                         errmsgno(err, "Cannot write '%s'\n", filename);
1714                         break;
1715                 }
1716         }
1717         fprintf(stderr, "addr: %8ld", addr);
1718 out:
1719         fprintf(stderr, "\n");
1720         msec = prstats();
1721         if (msec == 0)          /* Avoid division by zero */
1722                 msec = 1;
1723 #ifdef  OOO
1724         fprintf(stderr, "Read %.2f kB at %.1f kB/sec.\n",
1725                 (double)(addr - start)/(1024.0/usalp->cap->c_bsize),
1726                 (double)((addr - start)/(1024.0/usalp->cap->c_bsize)) / (0.001*msec));
1727 #else
1728         fprintf(stderr, "Read %.2f kB at %.1f kB/sec.\n",
1729                 (double)(addr - start)/(1024.0/secsize),
1730                 (double)((addr - start)/(1024.0/secsize)) / (0.001*msec));
1731 #endif
1732         print_bad();
1733 }
1734
1735 static void
1736 write_disk(SCSI *usalp, parm_t *parmp)
1737 {
1738         char    filename[512];
1739         char    *defname = "disk.out";
1740         FILE    *f;
1741         long    addr = 0L;
1742         long    cnt;
1743         long    amt;
1744         long    end;
1745         int     msec;
1746         int     start;
1747
1748         if (is_suid)
1749                 comerrno(EX_BAD, "Not root. Will not write in suid/priv mode\n");
1750
1751         filename[0] = '\0';
1752         if (read_capacity(usalp) >= 0) {
1753                 end = usalp->cap->c_baddr + 1;
1754                 print_capacity(usalp, stderr);
1755         }
1756
1757         if (end <= 1)
1758                 end = 10000000; /* Hack to write empty disks */
1759
1760         if (parmp) {
1761                 if (parmp->name)
1762                         defname = parmp->name;
1763                 fprintf(stderr, "Copy from file '%s' to SCSI (%d,%d,%d) disk\n",
1764                                         defname,
1765                                         usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
1766
1767                 addr = start = parmp->start;
1768                 if (parmp->end != -1 && parmp->end < end)
1769                         end = parmp->end;
1770                 cnt = Sbufsize / usalp->cap->c_bsize;
1771         } else {
1772                 fprintf(stderr, "Copy from file to SCSI (%d,%d,%d) disk\n",
1773                                         usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp));
1774                 fprintf(stderr, "Enter filename [%s]: ", defname); flush();
1775                 (void) rols_getline(filename, sizeof (filename));
1776                 fprintf(stderr, "Notice: reading from file always starts at file offset 0.\n");
1777
1778                 getlong("Enter starting sector for copy:", &addr, 0L, end-1);
1779                 start = addr;
1780                 cnt = end - addr;
1781                 getlong("Enter number of sectors to copy:", &end, 1L, end);
1782                 end = addr + cnt;
1783
1784                 cnt = Sbufsize / usalp->cap->c_bsize;
1785                 getlong("Enter number of sectors per copy:", &cnt, 1L, cnt);
1786 /*              fprintf(stderr, "end:  %8ld\n", end);*/
1787         }
1788
1789         if (filename[0] == '\0')
1790                 strncpy(filename, defname, sizeof (filename));
1791         filename[sizeof (filename)-1] = '\0';
1792         if (streql(filename, "-")) {
1793                 f = stdin;
1794 #ifdef  NEED_O_BINARY
1795                 setmode(STDIN_FILENO, O_BINARY);
1796 #endif
1797         } else if ((f = fileopen(filename, "rub")) == NULL)
1798                 comerr("Cannot open '%s'.\n", filename);
1799
1800         fprintf(stderr, "end:  %8ld\n", end);
1801         if (gettimeofday(&starttime, (struct timezone *)0) < 0)
1802                 comerr("Cannot get start time\n");
1803
1804         for (; addr < end; addr += cnt) {
1805                 if (didintr)
1806                         comexit(exsig);         /* XXX besseres Konzept?!*/
1807
1808                 if ((addr + cnt) > end)
1809                         cnt = end - addr;
1810
1811                 fprintf(stderr, "addr: %8ld cnt: %ld\r", addr, cnt);
1812
1813                 if ((amt = fileread(f, Sbuf, cnt * usalp->cap->c_bsize)) < 0)
1814                         comerr("Cannot read '%s'\n", filename);
1815                 if (amt == 0)
1816                         break;
1817                 if ((amt / usalp->cap->c_bsize) < cnt)
1818                         cnt = amt / usalp->cap->c_bsize;
1819                 if (write_scsi(usalp, Sbuf, addr, cnt) < 0)
1820                         comerrno(usalp->scmd->ux_errno,
1821                                         "Cannot write destination disk\n");
1822         }
1823         fprintf(stderr, "addr: %8ld\n", addr);
1824         msec = prstats();
1825         if (msec == 0)          /* Avoid division by zero */
1826                 msec = 1;
1827         fprintf(stderr, "Wrote %.2f kB at %.1f kB/sec.\n",
1828                 (double)(addr - start)/(1024.0/usalp->cap->c_bsize),
1829                 (double)((addr - start)/(1024.0/usalp->cap->c_bsize)) / (0.001*msec));
1830 }
1831
1832 static int
1833 choice(int n)
1834 {
1835 #if     defined(HAVE_DRAND48)
1836         extern  double  drand48(void);
1837
1838         return (drand48() * n);
1839 #else
1840 #       if      defined(HAVE_RAND)
1841         extern  int     rand(void);
1842
1843         return (rand() % n);
1844 #       else
1845         return (0);
1846 #       endif
1847 #endif
1848 }
1849
1850 static void
1851 ra(SCSI *usalp)
1852 {
1853 /*      char    filename[512];*/
1854         FILE    *f;
1855 /*      long    addr = 0L;*/
1856 /*      long    cnt;*/
1857 /*      long    end;*/
1858 /*      int     msec;*/
1859 /*      int     start;*/
1860 /*      int     err = 0;*/
1861
1862         select_secsize(usalp, 2352);
1863         read_capacity(usalp);
1864         print_capacity(usalp, stderr);
1865         fillbytes(Sbuf, 50*2352, 0);
1866         if (read_g1(usalp, Sbuf, 0, 50) < 0)
1867                 errmsg("read CD\n");
1868         f = fileopen("DDA", "wctb");
1869 /*      filewrite(f, Sbuf, 50 * 2352 - usal_getresid(usalp));*/
1870         filewrite(f, Sbuf, 50 * 2352);
1871         fclose(f);
1872 }
1873
1874 #define g5x_cdblen(cdb, len)    ((cdb)->count[0] = ((len) >> 16L)& 0xFF,\
1875                                 (cdb)->count[1] = ((len) >> 8L) & 0xFF,\
1876                                 (cdb)->count[2] = (len) & 0xFF)
1877
1878 int
1879 read_da(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, int subcode)
1880 {
1881         register struct usal_cmd        *scmd = usalp->scmd;
1882
1883         if (usalp->cap->c_bsize <= 0)
1884                 raisecond("capacity_not_set", 0L);
1885
1886         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1887         scmd->addr = bp;
1888         scmd->size = cnt*framesize;
1889         scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1890         scmd->cdb_len = SC_G5_CDBLEN;
1891         scmd->sense_len = CCS_SENSE_LEN;
1892         scmd->cdb.g5_cdb.cmd = 0xd8;
1893         scmd->cdb.g5_cdb.lun = usal_lun(usalp);
1894         g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
1895         g5_cdblen(&scmd->cdb.g5_cdb, cnt);
1896         scmd->cdb.g5_cdb.res10 = subcode;
1897
1898         usalp->cmdname = "read_da";
1899
1900         return (usal_cmd(usalp));
1901 }
1902
1903 int
1904 read_cd(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, int data, 
1905                   int subch)
1906 {
1907         register struct usal_cmd        *scmd = usalp->scmd;
1908
1909         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1910         scmd->addr = bp;
1911         scmd->size = cnt*framesize;
1912         scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1913         scmd->cdb_len = SC_G5_CDBLEN;
1914         scmd->sense_len = CCS_SENSE_LEN;
1915         scmd->cdb.g5_cdb.cmd = 0xBE;
1916         scmd->cdb.g5_cdb.lun = usal_lun(usalp);
1917         scmd->cdb.g5_cdb.res = 0;       /* expected sector type field ALL */
1918         g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
1919         g5x_cdblen(&scmd->cdb.g5_cdb, cnt);
1920
1921         scmd->cdb.g5_cdb.count[3] = data & 0xFF;
1922         scmd->cdb.g5_cdb.res10 = subch & 0x07;
1923
1924         usalp->cmdname = "read_cd";
1925
1926         return (usal_cmd(usalp));
1927 }
1928
1929 static void
1930 oldmode(SCSI *usalp, int *errp, int *retrp)
1931 {
1932         Uchar   mode[0x100];
1933         Uchar   cmode[0x100];
1934         Uchar   *p;
1935         int     i;
1936         int     len;
1937
1938         fillbytes(mode, sizeof (mode), '\0');
1939         fillbytes(cmode, sizeof (cmode), '\0');
1940
1941         if (!get_mode_params(usalp, 0x01, "CD error recovery parameter",
1942                         mode, (Uchar *)0, (Uchar *)cmode, (Uchar *)0, &len)) {
1943                 return;
1944         }
1945         if (xdebug)
1946                 usal_prbytes("Mode Sense Data", mode, len);
1947
1948         mode[0] = 0;
1949         mode[2] = 0; /* ??? ist manchmal 0x80 */
1950         p = mode;
1951         p += mode[3] + 4;
1952         *p &= 0x3F;
1953
1954         if (xdebug)
1955                 usal_prbytes("Mode page 1:", p, 0x10);
1956
1957         i = p[2];
1958         if (errp != NULL)
1959                 *errp = i;
1960
1961         i = p[3];
1962         if (retrp != NULL)
1963                 *retrp = i;
1964 }
1965
1966 static void
1967 domode(SCSI *usalp, int err, int retr)
1968 {
1969         Uchar   mode[0x100];
1970         Uchar   cmode[0x100];
1971         Uchar   *p;
1972         int     i;
1973         int     len;
1974
1975         fillbytes(mode, sizeof (mode), '\0');
1976         fillbytes(cmode, sizeof (cmode), '\0');
1977
1978         if (!get_mode_params(usalp, 0x01, "CD error recovery parameter",
1979                         mode, (Uchar *)0, (Uchar *)cmode, (Uchar *)0, &len)) {
1980                 return;
1981         }
1982         if (xdebug || (err == -1 && retr == -1)) {
1983                 usal_prbytes("Mode Sense Data", mode, len);
1984         }
1985
1986         mode[0] = 0;
1987         mode[2] = 0; /* ??? ist manchmal 0x80 */
1988         p = mode;
1989         p += mode[3] + 4;
1990         *p &= 0x3F;
1991
1992         if (xdebug || (err == -1 && retr == -1))
1993                 usal_prbytes("Mode page 1:", p, 0x10);
1994
1995         i = p[2];
1996         if (err == -1) {
1997                 getint("Error handling? ", &i, 0, 255);
1998                 p[2] = i;
1999         } else {
2000                 if (xdebug)
2001                         fprintf(stderr, "Error handling set from %02X to %02X\n",
2002                 p[2], err);
2003                 p[2] = err;
2004         }
2005
2006         i = p[3];
2007         if (retr == -1) {
2008                 getint("Retry count? ", &i, 0, 255);
2009                 p[3] = i;
2010         } else {
2011                 if (xdebug)
2012                         fprintf(stderr, "Retry count set from %d to %d\n",
2013                 p[3] & 0xFF, retr);
2014                 p[3] = retr;
2015         }
2016
2017         if (xdebug || (err == -1 && retr == -1))
2018                 usal_prbytes("Mode Select Data", mode, len);
2019         mode_select(usalp, mode, len, 0, usalp->inq->data_format >= 2);
2020 }
2021
2022
2023 /*--------------------------------------------------------------------------*/
2024 static  void    qpto96(Uchar *sub, Uchar *subq, int dop);
2025 /*EXPORT        void    qpto96          __PR((Uchar *sub, Uchar *subq, int dop));*/
2026 /*
2027  * Q-Sub auf 96 Bytes blähen und P-Sub addieren
2028  *
2029  * OUT: sub, IN: subqptr
2030  */
2031 static void
2032 /*EXPORT void*/
2033 qpto96(Uchar *sub, Uchar *subqptr, int dop)
2034 {
2035         Uchar   tmp[16];
2036         Uchar   *p;
2037         int     c;
2038         int     i;
2039
2040         if (subqptr == sub) {
2041                 movebytes(subqptr, tmp, 12);
2042                 subqptr = tmp;
2043         }
2044         fillbytes(sub, 96, '\0');
2045
2046         /* CSTYLED */
2047         if (dop) for (i = 0, p = sub; i < 96; i++) {
2048                 *p++ |= 0x80;
2049         }
2050         for (i = 0, p = sub; i < 12; i++) {
2051                 c = subqptr[i] & 0xFF;
2052 /*printf("%02X\n", c);*/
2053                 if (c & 0x80)
2054                         *p++ |= 0x40;
2055                 else
2056                         p++;
2057                 if (c & 0x40)
2058                         *p++ |= 0x40;
2059                 else
2060                         p++;
2061                 if (c & 0x20)
2062                         *p++ |= 0x40;
2063                 else
2064                         p++;
2065                 if (c & 0x10)
2066                         *p++ |= 0x40;
2067                 else
2068                         p++;
2069                 if (c & 0x08)
2070                         *p++ |= 0x40;
2071                 else
2072                         p++;
2073                 if (c & 0x04)
2074                         *p++ |= 0x40;
2075                 else
2076                         p++;
2077                 if (c & 0x02)
2078                         *p++ |= 0x40;
2079                 else
2080                         p++;
2081                 if (c & 0x01)
2082                         *p++ |= 0x40;
2083                 else
2084                         p++;
2085         }
2086 }
2087
2088 /*--------------------------------------------------------------------------*/
2089
2090 static void
2091 ovtime(SCSI *usalp)
2092 {
2093         register int    i;
2094
2095         usalp->silent++;
2096         (void) test_unit_ready(usalp);
2097         usalp->silent--;
2098         if (test_unit_ready(usalp) < 0)
2099                 return;
2100
2101         printf("Doing 1000 'TEST UNIT READY' operations.\n");
2102
2103         if (gettimeofday(&starttime, (struct timezone *)0) < 0)
2104                 comerr("Cannot get start time\n");
2105
2106         for (i = 1000; --i >= 0; ) {
2107                 (void) test_unit_ready(usalp);
2108
2109                 if (didintr)
2110                         return;
2111         }
2112
2113         prstats();
2114
2115         /*
2116          * ATAPI drives do not like seek_g0()
2117          */
2118         usalp->silent++;
2119         i = seek_g0(usalp, 0L);
2120         usalp->silent--;
2121
2122         if (i >= 0) {
2123                 printf("Doing 1000 'SEEK_G0 (0)' operations.\n");
2124
2125                 if (gettimeofday(&starttime, (struct timezone *)0) < 0)
2126                         comerr("Cannot get start time\n");
2127
2128                 for (i = 1000; --i >= 0; ) {
2129                         (void) seek_g0(usalp, 0L);
2130
2131                         if (didintr)
2132                                 return;
2133                 }
2134
2135                 prstats();
2136         }
2137
2138         usalp->silent++;
2139         i = seek_g1(usalp, 0L);
2140         usalp->silent--;
2141         if (i < 0)
2142                 return;
2143
2144         printf("Doing 1000 'SEEK_G1 (0)' operations.\n");
2145
2146         if (gettimeofday(&starttime, (struct timezone *)0) < 0)
2147                 comerr("Cannot get start time\n");
2148
2149         for (i = 1000; --i >= 0; ) {
2150                 (void) seek_g1(usalp, 0L);
2151
2152                 if (didintr)
2153                         return;
2154         }
2155
2156         prstats();
2157 }
2158
2159 #define BAD_INC         16
2160 long    *badsecs;
2161 int     nbad;
2162 int     maxbad;
2163
2164 static void
2165 add_bad(long addr)
2166 {
2167         if (maxbad == 0) {
2168                 maxbad = BAD_INC;
2169                 badsecs = malloc(maxbad * sizeof (long));
2170                 if (badsecs == NULL)
2171                         comerr("No memory for bad sector list\n.");
2172         }
2173         if (nbad >= maxbad) {
2174                 maxbad += BAD_INC;
2175                 badsecs = realloc(badsecs, maxbad * sizeof (long));
2176                 if (badsecs == NULL)
2177                         comerr("No memory to grow bad sector list\n.");
2178         }
2179         badsecs[nbad++] = addr;
2180 }
2181
2182 static void
2183 print_bad(void)
2184 {
2185         int     i;
2186
2187         if (nbad == 0)
2188                 return;
2189
2190         fprintf(stderr, "Max corected retry count was %d (limited to %d).\n", maxtry, retries);
2191         fprintf(stderr, "The following %d sector(s) could not be read correctly:\n", nbad);
2192         for (i = 0; i < nbad; i++)
2193                 fprintf(stderr, "%ld\n", badsecs[i]);
2194 }