/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)readcd.c 1.80 06/02/05 Copyright 1987, 1995-2006 J. Schilling */ /* * Skeleton for the use of the usal genearal SCSI - driver * * Copyright (c) 1987, 1995-2004 J. Schilling */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_PRIV_H #include #endif #ifdef NEED_O_BINARY #include /* for setmode() prototype */ #endif #include #include #include #include "scsi_scan.h" #include "scsimmc.h" #define qpto96 __nothing__ #include "wodim.h" #include "defaults.h" #undef qpto96 #include "movesect.h" char cdr_version[] = "2.01.01a05"; #if defined(PROTOTYPES) #define UINT_C(a) (a##u) #define ULONG_C(a) (a##ul) #define USHORT_C(a) (a##uh) #define CONCAT(a, b) a##b #else #define UINT_C(a) ((unsigned)(a)) #define ULONG_C(a) ((unsigned long)(a)) #define USHORT_C(a) ((unsigned short)(a)) /* CSTYLED */ #define CONCAT(a, b) a/**/b #endif extern BOOL getlong(char *, long *, long, long); extern BOOL getint(char *, int *, int, int); typedef struct { long start; long end; long sptr; /* sectors per transfer */ BOOL askrange; char *name; } parm_t; typedef struct { int errors; int c2_errors; int c2_maxerrs; int c2_errsecs; int c2_badsecs; int secsize; BOOL ismmc; } rparm_t; struct exargs { SCSI *usalp; int old_secsize; int flags; int exflags; char oerr[3]; } exargs; BOOL cvt_cyls(void); BOOL cvt_bcyls(void); void print_defect_list(void); static void usage(int ret); static void intr(int sig); static void exscsi(int excode, void *arg); static void excdr(int excode, void *arg); static int prstats(void); static int prstats_silent(void); static void dorw(SCSI *usalp, char *filename, char *sectors); static void doit(SCSI *usalp); static void read_disk(SCSI *usalp, parm_t *parmp); #ifdef CLONE_WRITE static void readcd_disk(SCSI *usalp, parm_t *parmp); static void read_lin(SCSI *usalp, parm_t *parmp); static int read_secheader(SCSI *usalp, long addr); static int read_ftoc(SCSI *usalp, parm_t *parmp, BOOL do_sectype); static void read_sectypes(SCSI *usalp, FILE *f); static void get_sectype(SCSI *usalp, long addr, char *st); #endif static void readc2_disk(SCSI *usalp, parm_t *parmp); static int fread_data(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt); #ifdef CLONE_WRITE static int fread_2448(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt); static int fread_2448_16(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt); static int fread_2352(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt); static int fread_lin(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt); #endif static int bits(int c); static int bitidx(int c); static int fread_c2(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt); static int fdata_null(rparm_t *rp, caddr_t bp, long addr, int cnt); static int fdata_c2(rparm_t *rp, caddr_t bp, long addr, int cnt); #ifdef used static int read_scsi_g1(SCSI *usalp, caddr_t bp, long addr, int cnt); #endif int write_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt); int write_g0(SCSI *usalp, caddr_t bp, long addr, int cnt); int write_g1(SCSI *usalp, caddr_t bp, long addr, int cnt); #ifdef used static void Xrequest_sense(SCSI *usalp); #endif static int read_retry(SCSI *usalp, caddr_t bp, long addr, long cnt, int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt), rparm_t *rp); static void read_generic(SCSI *usalp, parm_t *parmp, int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt), rparm_t *rp, int (*dfunc)(rparm_t *rp, caddr_t bp, long addr, int cnt)); static void write_disk(SCSI *usalp, parm_t *parmp); static int choice(int n); static void ra(SCSI *usalp); int read_da(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, int subcode); int read_cd(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, int data, int subch); static void oldmode(SCSI *usalp, int *errp, int *retrp); static void domode(SCSI *usalp, int err, int retr); static void qpto96(Uchar *sub, Uchar *subq, int dop); static void ovtime(SCSI *usalp); static void add_bad(long addr); static void print_bad(void); struct timeval starttime; struct timeval stoptime; int didintr; int exsig; char *Sbuf; long Sbufsize; /*#define MAX_RETRY 32*/ #define MAX_RETRY 128 int help; int xdebug; int lverbose; int quiet; BOOL is_suid; BOOL is_cdrom; BOOL is_dvd; BOOL do_write; BOOL c2scan; BOOL fulltoc; BOOL clonemode; BOOL noerror; BOOL nocorr; BOOL notrunc; int retries = MAX_RETRY; int maxtry = 0; int meshpoints; BOOL do_factor; struct scsi_format_data fmt; /*XXX*/EXPORT BOOL cvt_cyls(void) { return (FALSE); } /*XXX*/EXPORT BOOL cvt_bcyls(void) { return (FALSE); } /*XXX*/EXPORT void print_defect_list(void) {} static void usage(int ret) { fprintf(stderr, "Usage:\treadom [options]\n"); fprintf(stderr, "options:\n"); fprintf(stderr, "\t-version print version information and exit\n"); fprintf(stderr, "\tdev=target SCSI target to use\n"); fprintf(stderr, "\tf=filename Name of file to read/write\n"); fprintf(stderr, "\tsectors=range Range of sectors to read/write\n"); fprintf(stderr, "\tspeed=# set speed of drive (MMC only)\n"); fprintf(stderr, "\tts=# set maximum transfer size for a single SCSI command\n"); fprintf(stderr, "\t-w Switch to write mode\n"); fprintf(stderr, "\t-c2scan Do a C2 error scan\n"); #ifdef CLONE_WRITE fprintf(stderr, "\t-fulltoc Retrieve the full TOC\n"); fprintf(stderr, "\t-clone Retrieve the full TOC and all data\n"); #endif fprintf(stderr, "\ttimeout=# set the default SCSI command timeout to #.\n"); fprintf(stderr, "\tdebug=#,-d Set to # or increment misc debug level\n"); fprintf(stderr, "\tkdebug=#,kd=# do Kernel debugging\n"); fprintf(stderr, "\t-quiet,-q be more quiet in error retry mode\n"); fprintf(stderr, "\t-verbose,-v increment general verbose level by one\n"); fprintf(stderr, "\t-Verbose,-V increment SCSI command transport verbose level by one\n"); fprintf(stderr, "\t-silent,-s do not print status of failed SCSI commands\n"); fprintf(stderr, "\t-scanbus scan the SCSI bus and exit\n"); fprintf(stderr, "\t-noerror do not abort on error\n"); #ifdef CLONE_WRITE fprintf(stderr, "\t-nocorr do not apply error correction in drive\n"); #endif fprintf(stderr, "\t-notrunc do not truncate outputfile in read mode\n"); fprintf(stderr, "\tretries=# set retry count (default is %d)\n", retries); fprintf(stderr, "\t-overhead meter SCSI command overhead times\n"); fprintf(stderr, "\tmeshpoints=# print read-speed at # locations\n"); fprintf(stderr, "\t-factor try to use speed factor with meshpoints=# if possible\n"); fprintf(stderr, "\n"); fprintf(stderr, "sectors=0-0 will read nothing, sectors=0-1 will read one sector starting from 0\n"); exit(ret); } /* CSTYLED */ 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#"; int main(int argc, char *argv[]) { char *dev = NULL; int fcount; int cac; char * const *cav; int scsibus = -1; int target = -1; int lun = -1; int silent = 0; int verbose = 0; int kdebug = 0; int debug = 0; int deftimeout = 40; int pversion = 0; int scanbus = 0; int speed = -1; int dooverhead = 0; SCSI *usalp; char *filename = NULL; char *sectors = NULL; save_args(argc, argv); cac = --argc; cav = ++argv; if (getallargs(&cac, &cav, opts, &debug, &debug, &kdebug, &kdebug, &deftimeout, &quiet, &quiet, &lverbose, &lverbose, &verbose, &verbose, &xdebug, &xdebug, &silent, &silent, &help, &help, &pversion, &scanbus, &dev, §ors, &do_write, &c2scan, &fulltoc, &clonemode, &noerror, &nocorr, ¬runc, &retries, &do_factor, &filename, &speed, getnum, &Sbufsize, &dooverhead, &meshpoints) < 0) { errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]); usage(EX_BAD); } if (help) usage(0); if (pversion) { printf("readcd %s is not what you see here. This line is only a fake for too clever\n" "GUIs and other frontend applications. In fact, this program is:\n", cdr_version); printf("readom " CDRKIT_VERSION " (" HOST_SYSTEM ")\n" "Copyright (C) 1987, 1995-2006 Joerg Schilling\n" "Copyright (C) 2006 Cdrkit maintainers\n" "(modified version of -- " "don't bother Joerg Schilling with problems)\n"); exit(0); } fcount = 0; cac = argc; cav = argv; while (getfiles(&cac, &cav, opts) > 0) { fcount++; if (fcount == 1) { if (*astoi(cav[0], &target) != '\0') { errmsgno(EX_BAD, "Target '%s' is not a Number.\n", cav[0]); usage(EX_BAD); /* NOTREACHED */ } } if (fcount == 2) { if (*astoi(cav[0], &lun) != '\0') { errmsgno(EX_BAD, "Lun is '%s' not a Number.\n", cav[0]); usage(EX_BAD); /* NOTREACHED */ } } if (fcount == 3) { if (*astoi(cav[0], &scsibus) != '\0') { errmsgno(EX_BAD, "Scsibus is '%s' not a Number.\n", cav[0]); usage(EX_BAD); /* NOTREACHED */ } } cac--; cav++; } /*fprintf(stderr, "dev: '%s'\n", dev);*/ if (!scanbus) cdr_defaults(&dev, NULL, NULL, NULL); if (debug) { printf("dev: '%s'\n", dev); } if (!scanbus && dev == NULL && scsibus == -1 && (target == -1 || lun == -1)) { errmsgno(EX_BAD, "No SCSI device specified.\n"); usage(EX_BAD); } if (dev || scanbus) { char errstr[80]; /* * Call usal_remote() to force loading the remote SCSI transport * library code that is located in librusal instead of the dummy * remote routines that are located inside libusal. */ usal_remote(); if (dev != NULL && ((strncmp(dev, "HELP", 4) == 0) || (strncmp(dev, "help", 4) == 0))) { usal_help(stderr); exit(0); } if ((usalp = usal_open(dev, errstr, sizeof (errstr), debug, lverbose)) == (SCSI *)0) { int err = geterrno(); errmsgno(err, "%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":""); errmsgno(EX_BAD, "For possible targets try 'wodim -scanbus'.%s\n", geteuid() ? " Make sure you are root.":""); errmsgno(EX_BAD, "For possible transport specifiers try 'wodim dev=help'.\n"); exit(err); } } else { if (scsibus == -1 && target >= 0 && lun >= 0) scsibus = 0; usalp = usal_smalloc(); usalp->debug = debug; usalp->kdebug = kdebug; usal_settarget(usalp, scsibus, target, lun); if (usal__open(usalp, NULL) <= 0) comerr("Cannot open SCSI driver.\n"); } usalp->silent = silent; usalp->verbose = verbose; usalp->debug = debug; usalp->kdebug = kdebug; usal_settimeout(usalp, deftimeout); if (Sbufsize == 0) Sbufsize = 256*1024L; Sbufsize = usal_bufsize(usalp, Sbufsize); if ((Sbuf = usal_getbuf(usalp, Sbufsize)) == NULL) comerr("Cannot get SCSI I/O buffer.\n"); #ifdef HAVE_PRIV_SET is_suid = priv_ineffect(PRIV_FILE_DAC_READ) && !priv_ineffect(PRIV_PROC_SETID); /* * Give up privs we do not need anymore. * We no longer need: * file_dac_read,net_privaddr * We still need: * sys_devices */ priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL); priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL); priv_set(PRIV_OFF, PRIV_INHERITABLE, PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL); #endif /* * This is only for OS that do not support fine grained privs. */ if (!is_suid) is_suid = geteuid() != getuid(); /* * We don't need root privilleges anymore. */ #ifdef HAVE_SETREUID if (setreuid(-1, getuid()) < 0) #else #ifdef HAVE_SETEUID if (seteuid(getuid()) < 0) #else if (setuid(getuid()) < 0) #endif #endif comerr("Panic cannot set back effective uid.\n"); /* code to use SCG */ if (scanbus) { select_target(usalp, stdout); exit(0); } do_inquiry(usalp, FALSE); allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */ if (is_mmc(usalp, NULL, NULL)) { int rspeed; int wspeed; /* * At this point we know that we have a SCSI-3/mmc compliant drive. * Unfortunately ATAPI drives violate the SCSI spec in returning * a response data format of '1' which from the SCSI spec would * tell us not to use the "PF" bit in mode select. As ATAPI drives * require the "PF" bit to be set, we 'correct' the inquiry data. */ if (usalp->inq->data_format < 2) usalp->inq->data_format = 2; if ((rspeed = get_curprofile(usalp)) >= 0) { if (rspeed >= 0x08 && rspeed < 0x10) is_cdrom = TRUE; if (rspeed >= 0x10 && rspeed < 0x20) is_dvd = TRUE; } else { BOOL dvd; mmc_check(usalp, NULL, NULL, NULL, NULL, &dvd, NULL); if (dvd == FALSE) { is_cdrom = TRUE; } else { char xb[32]; if (read_dvd_structure(usalp, (caddr_t)xb, 32, 0, 0, 0) >= 0) { /* * If read DVD structure is supported and works, then * we must have a DVD media in the drive. Signal to * use the DVD driver. */ is_dvd = TRUE; } else { is_cdrom = TRUE; } } } if (speed > 0) speed *= 177; if (speed > 0xFFFF || speed < 0) speed = 0xFFFF; scsi_set_speed(usalp, speed, speed, ROTCTL_CLV); if (scsi_get_speed(usalp, &rspeed, &wspeed) >= 0) { fprintf(stderr, "Read speed: %5d kB/s (CD %3dx, DVD %2dx).\n", rspeed, rspeed/176, rspeed/1385); fprintf(stderr, "Write speed: %5d kB/s (CD %3dx, DVD %2dx).\n", wspeed, wspeed/176, wspeed/1385); } } exargs.usalp = usalp; exargs.old_secsize = -1; /* exargs.flags = flags;*/ exargs.oerr[2] = 0; /* * Install exit handler before we change the drive status. */ on_comerr(exscsi, &exargs); signal(SIGINT, intr); signal(SIGTERM, intr); if (dooverhead) { ovtime(usalp); comexit(0); } if (is_suid) { if (usalp->inq->type != INQ_ROMD) comerrno(EX_BAD, "Not root. Will only work on CD-ROM in suid/priv mode\n"); } if (filename || sectors || c2scan || meshpoints || fulltoc || clonemode) { dorw(usalp, filename, sectors); } else { doit(usalp); } comexit(0); return (0); } /* * XXX Leider kann man vim Signalhandler keine SCSI Kommandos verschicken * XXX da meistens das letzte SCSI Kommando noch laeuft. * XXX Eine Loesung waere ein Abort Callback in SCSI *. */ static void intr(int sig) { didintr++; exsig = sig; /* comexit(sig);*/ } /* ARGSUSED */ static void exscsi(int excode, void *arg) { struct exargs *exp = (struct exargs *)arg; int i; /* * Try to restore the old sector size. */ if (exp != NULL && exp->exflags == 0) { for (i = 0; i < 10*100; i++) { if (!exp->usalp->running) break; if (i == 10) { errmsgno(EX_BAD, "Waiting for current SCSI command to finish.\n"); } usleep(100000); } if (!exp->usalp->running) { if (exp->oerr[2] != 0) { domode(exp->usalp, exp->oerr[0], exp->oerr[1]); } if (exp->old_secsize > 0 && exp->old_secsize != 2048) select_secsize(exp->usalp, exp->old_secsize); } exp->exflags++; /* Make sure that it only get called once */ } } static void excdr(int excode, void *arg) { exscsi(excode, arg); #ifdef needed /* Do several other restores/statistics here (see cdrecord.c) */ #endif } /* * Return milliseconds since start time. */ static int prstats(void) { int sec; int usec; int tmsec; if (gettimeofday(&stoptime, (struct timezone *)0) < 0) comerr("Cannot get time\n"); sec = stoptime.tv_sec - starttime.tv_sec; usec = stoptime.tv_usec - starttime.tv_usec; tmsec = sec*1000 + usec/1000; #ifdef lint tmsec = tmsec; /* Bisz spaeter */ #endif if (usec < 0) { sec--; usec += 1000000; } fprintf(stderr, "Time total: %d.%03dsec\n", sec, usec/1000); return (1000*sec + (usec / 1000)); } /* * Return milliseconds since start time, but be silent this time. */ static int prstats_silent(void) { int sec; int usec; int tmsec; if (gettimeofday(&stoptime, (struct timezone *)0) < 0) comerr("Cannot get time\n"); sec = stoptime.tv_sec - starttime.tv_sec; usec = stoptime.tv_usec - starttime.tv_usec; tmsec = sec*1000 + usec/1000; #ifdef lint tmsec = tmsec; /* Bisz spaeter */ #endif if (usec < 0) { sec--; usec += 1000000; } return (1000*sec + (usec / 1000)); } static void dorw(SCSI *usalp, char *filename, char *sectors) { parm_t params; char *p = NULL; params.start = 0; params.end = -1; params.sptr = -1; params.askrange = FALSE; params.name = NULL; if (filename) params.name = filename; if (meshpoints > 0) { if (params.name == NULL) params.name = "/dev/null"; } if (sectors) p = astol(sectors, ¶ms.start); if (p && *p == '-') p = astol(++p, ¶ms.end); if (p && *p != '\0') comerrno(EX_BAD, "Not a valid sector range '%s'\n", sectors); if (!wait_unit_ready(usalp, 60)) comerrno(EX_BAD, "Device not ready.\n"); #ifdef CLONE_WRITE if (fulltoc) { if (params.name == NULL) params.name = "/dev/null"; read_ftoc(usalp, ¶ms, FALSE); } else if (clonemode) { if (!is_mmc(usalp, NULL, NULL)) comerrno(EX_BAD, "Unsupported device for clone mode.\n"); noerror = TRUE; if (retries == MAX_RETRY) retries = 10; if (params.name == NULL) params.name = "/dev/null"; if (read_ftoc(usalp, ¶ms, TRUE) < 0) comerrno(EX_BAD, "Read fulltoc problems.\n"); readcd_disk(usalp, ¶ms); } else #endif if (c2scan) { noerror = TRUE; if (retries == MAX_RETRY) retries = 10; if (params.name == NULL) params.name = "/dev/null"; readc2_disk(usalp, ¶ms); } else if (do_write) write_disk(usalp, ¶ms); else read_disk(usalp, ¶ms); } static void doit(SCSI *usalp) { int i = 0; parm_t params; params.start = 0; params.end = -1; params.sptr = -1; params.askrange = TRUE; params.name = "/dev/null"; for (;;) { if (!wait_unit_ready(usalp, 60)) comerrno(EX_BAD, "Device not ready.\n"); printf("0:read 1:veri 2:erase 3:read buffer 4:cache 5:ovtime 6:cap\n"); printf("7:wne 8:floppy 9:verify 10:checkcmds 11:read disk 12:write disk\n"); printf("13:scsireset 14:seektest 15: readda 16: reada 17: c2err\n"); #ifdef CLONE_WRITE printf("18:readom 19: lin 20: full toc\n"); #endif getint("Enter selection:", &i, 0, 20); if (didintr) return; switch (i) { case 5: ovtime(usalp); break; case 11: read_disk(usalp, 0); break; case 12: write_disk(usalp, 0); break; case 15: ra(usalp); break; /* case 16: reada_disk(usalp, 0, 0); break;*/ case 17: readc2_disk(usalp, ¶ms); break; #ifdef CLONE_WRITE case 18: readcd_disk(usalp, 0); break; case 19: read_lin(usalp, 0); break; case 20: read_ftoc(usalp, 0, FALSE); break; #endif } } } static void read_disk(SCSI *usalp, parm_t *parmp) { rparm_t rp; read_capacity(usalp); print_capacity(usalp, stderr); rp.errors = 0; rp.c2_errors = 0; rp.c2_maxerrs = 0; rp.c2_errsecs = 0; rp.c2_badsecs = 0; rp.secsize = usalp->cap->c_bsize; read_generic(usalp, parmp, fread_data, &rp, fdata_null); } #ifdef CLONE_WRITE static void readcd_disk(SCSI *usalp, parm_t *parmp) { rparm_t rp; int osecsize = 2048; int oerr = 0; int oretr = 10; int (*funcp)(SCSI *_usalp, rparm_t *_rp, caddr_t bp, long addr, int cnt); usalp->silent++; if (read_capacity(usalp) >= 0) osecsize = usalp->cap->c_bsize; usalp->silent--; if (osecsize != 2048) select_secsize(usalp, 2048); read_capacity(usalp); print_capacity(usalp, stderr); rp.errors = 0; rp.c2_errors = 0; rp.c2_maxerrs = 0; rp.c2_errsecs = 0; rp.c2_badsecs = 0; rp.secsize = 2448; rp.ismmc = is_mmc(usalp, NULL, NULL); funcp = fread_2448; wait_unit_ready(usalp, 10); if (fread_2448(usalp, &rp, Sbuf, 0, 0) < 0) { errmsgno(EX_BAD, "read 2448 failed\n"); if (rp.ismmc && fread_2448_16(usalp, &rp, Sbuf, 0, 0) >= 0) { errmsgno(EX_BAD, "read 2448_16 : OK\n"); funcp = fread_2448_16; } } oldmode(usalp, &oerr, &oretr); exargs.oerr[0] = oerr; exargs.oerr[1] = oretr; exargs.oerr[2] = 0xFF; if (parmp == NULL) /* XXX Nur am Anfang!!! */ domode(usalp, -1, -1); else domode(usalp, nocorr?0x21:0x20, 10); read_generic(usalp, parmp, funcp, &rp, fdata_null); if (osecsize != 2048) select_secsize(usalp, osecsize); domode(usalp, oerr, oretr); } /* ARGSUSED */ static void read_lin(SCSI *usalp, parm_t *parmp) { parm_t parm; rparm_t rp; read_capacity(usalp); print_capacity(usalp, stderr); parm.start = ULONG_C(0xF0000000); parm.end = ULONG_C(0xFF000000); parm.name = "DDD"; rp.errors = 0; rp.c2_errors = 0; rp.c2_maxerrs = 0; rp.c2_errsecs = 0; rp.c2_badsecs = 0; rp.secsize = 2448; rp.ismmc = is_mmc(usalp, NULL, NULL); domode(usalp, -1, -1); read_generic(usalp, &parm, fread_lin, &rp, fdata_null); } static int read_secheader(SCSI *usalp, long addr) { rparm_t rp; int osecsize = 2048; int ret = 0; usalp->silent++; if (read_capacity(usalp) >= 0) osecsize = usalp->cap->c_bsize; usalp->silent--; if (osecsize != 2048) select_secsize(usalp, 2048); read_capacity(usalp); rp.errors = 0; rp.c2_errors = 0; rp.c2_maxerrs = 0; rp.c2_errsecs = 0; rp.c2_badsecs = 0; rp.secsize = 2352; rp.ismmc = is_mmc(usalp, NULL, NULL); wait_unit_ready(usalp, 10); fillbytes(Sbuf, 2352, '\0'); if (fread_2352(usalp, &rp, Sbuf, addr, 1) < 0) { ret = -1; } if (osecsize != 2048) select_secsize(usalp, osecsize); return (ret); } /* ARGSUSED */ static int read_ftoc(SCSI *usalp, parm_t *parmp, BOOL do_sectype) { FILE *f; int i; char filename[1024]; struct tocheader *tp; char *p; char xb[256]; int len; char xxb[10000]; strcpy(filename, "toc.dat"); if (strcmp(parmp->name, "/dev/null") != 0) { len = strlen(parmp->name); if (len > (sizeof (filename)-5)) { len = sizeof (filename)-5; } snprintf(filename, sizeof (filename), "%.*s.toc", len, parmp->name); } tp = (struct tocheader *)xb; fillbytes((caddr_t)xb, sizeof (xb), '\0'); if (read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_FULLTOC) < 0) { if (usalp->silent == 0 || usalp->verbose > 0) errmsgno(EX_BAD, "Cannot read TOC header\n"); return (-1); } len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2; fprintf(stderr, "TOC len: %d. First Session: %d Last Session: %d.\n", len, tp->first, tp->last); if (read_toc(usalp, xxb, 0, len, 0, FMT_FULLTOC) < 0) { if (len & 1) { /* * Work around a bug in some operating systems that do not * handle odd byte DMA correctly for ATAPI drives. */ wait_unit_ready(usalp, 30); read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_FULLTOC); wait_unit_ready(usalp, 30); if (read_toc(usalp, xxb, 0, len+1, 0, FMT_FULLTOC) >= 0) { goto itworked; } } if (usalp->silent == 0) errmsgno(EX_BAD, "Cannot read full TOC\n"); return (-1); } itworked: f = fileopen(filename, "wctb"); if (f == NULL) comerr("Cannot open '%s'.\n", filename); filewrite(f, xxb, len); if (do_sectype) read_sectypes(usalp, f); fflush(f); fclose(f); p = &xxb[4]; for (; p < &xxb[len]; p += 11) { for (i = 0; i < 11; i++) fprintf(stderr, "%02X ", p[i] & 0xFF); fprintf(stderr, "\n"); } /* * List all lead out start times to give information about multi * session disks. */ p = &xxb[4]; for (; p < &xxb[len]; p += 11) { if ((p[3] & 0xFF) == 0xA2) { fprintf(stderr, "Lead out %d: %ld\n", p[0], msf_to_lba(p[8], p[9], p[10], TRUE)); } } return (0); } static void read_sectypes(SCSI *usalp, FILE *f) { char sect; sect = SECT_AUDIO; get_sectype(usalp, 4, §); if (f != NULL) filewrite(f, §, 1); if (xdebug) usal_prbytes("sec 0", (Uchar *)Sbuf, 16); sect = SECT_AUDIO; get_sectype(usalp, usalp->cap->c_baddr-4, §); if (f != NULL) filewrite(f, §, 1); if (xdebug) { usal_prbytes("sec E", (Uchar *)Sbuf, 16); fprintf(stderr, "baddr: %ld\n", (long)usalp->cap->c_baddr); } } static void get_sectype(SCSI *usalp, long addr, char *st) { char *synchdr = "\0\377\377\377\377\377\377\377\377\377\377\0"; int sectype = SECT_AUDIO; int i; long raddr = addr; #define _MAX_TRY_ 20 usalp->silent++; for (i = 0; i < _MAX_TRY_ && read_secheader(usalp, raddr) < 0; i++) { if (addr == 0) raddr++; else raddr--; } usalp->silent--; if (i >= _MAX_TRY_) { fprintf(stderr, "Sectype (%ld) is CANNOT\n", addr); return; } else if (i > 0) { fprintf(stderr, "Sectype (%ld) needed %d retries\n", addr, i); } #undef _MAX_TRY_ if (cmpbytes(Sbuf, synchdr, 12) < 12) { if (xdebug) fprintf(stderr, "Sectype (%ld) is AUDIO\n", addr); if (st) *st = SECT_AUDIO; return; } if (xdebug) fprintf(stderr, "Sectype (%ld) is DATA\n", addr); if (Sbuf[15] == 0) { if (xdebug) fprintf(stderr, "Sectype (%ld) is MODE 0\n", addr); sectype = SECT_MODE_0; } else if (Sbuf[15] == 1) { if (xdebug) fprintf(stderr, "Sectype (%ld) is MODE 1\n", addr); sectype = SECT_ROM; } else if (Sbuf[15] == 2) { if (xdebug) fprintf(stderr, "Sectype (%ld) is MODE 2\n", addr); if ((Sbuf[16+2] & 0x20) == 0 && (Sbuf[16+4+2] & 0x20) == 0) { if (xdebug) fprintf(stderr, "Sectype (%ld) is MODE 2 form 1\n", addr); sectype = SECT_MODE_2_F1; } else if ((Sbuf[16+2] & 0x20) != 0 && (Sbuf[16+4+2] & 0x20) != 0) { if (xdebug) fprintf(stderr, "Sectype (%ld) is MODE 2 form 2\n", addr); sectype = SECT_MODE_2_F2; } else { if (xdebug) fprintf(stderr, "Sectype (%ld) is MODE 2 formless\n", addr); sectype = SECT_MODE_2; } } else { fprintf(stderr, "Sectype (%ld) is UNKNOWN\n", addr); } if (st) *st = sectype; if (xdebug) fprintf(stderr, "Sectype (%ld) is 0x%02X\n", addr, sectype); } #endif /* CLONE_WRITE */ char zeroblk[512]; static void readc2_disk(SCSI *usalp, parm_t *parmp) { rparm_t rp; int osecsize = 2048; int oerr = 0; int oretr = 10; usalp->silent++; if (read_capacity(usalp) >= 0) osecsize = usalp->cap->c_bsize; usalp->silent--; if (osecsize != 2048) select_secsize(usalp, 2048); read_capacity(usalp); print_capacity(usalp, stderr); rp.errors = 0; rp.c2_errors = 0; rp.c2_maxerrs = 0; rp.c2_errsecs = 0; rp.c2_badsecs = 0; rp.secsize = 2352 + 294; rp.ismmc = is_mmc(usalp, NULL, NULL); oldmode(usalp, &oerr, &oretr); exargs.oerr[0] = oerr; exargs.oerr[1] = oretr; exargs.oerr[2] = 0xFF; domode(usalp, 0x21, 10); read_generic(usalp, parmp, fread_c2, &rp, fdata_c2); if (osecsize != 2048) select_secsize(usalp, osecsize); domode(usalp, oerr, oretr); printf("Total of %d hard read errors.\n", rp.errors); printf("C2 errors total: %d bytes in %d sectors on disk\n", rp.c2_errors, rp.c2_errsecs); printf("C2 errors rate: %f%% \n", (100.0*rp.c2_errors)/usalp->cap->c_baddr/2352); printf("C2 errors on worst sector: %d, sectors with 100+ C2 errors: %d\n", rp.c2_maxerrs, rp.c2_badsecs); } /* ARGSUSED */ static int fread_data(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt) { return (read_g1(usalp, bp, addr, cnt)); } #ifdef CLONE_WRITE static int fread_2448(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt) { if (rp->ismmc) { return (read_cd(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC */ (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3), /* plus all subchannels RAW */ 1)); } else { return (read_da(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC + all subch */ 0x02)); } } static int fread_2448_16(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt) { if (rp->ismmc) { track_t trackdesc; int ret; int i; char *p; trackdesc.isecsize = 2368; trackdesc.secsize = 2448; ret = read_cd(usalp, bp, addr, cnt, 2368, /* Sync + all headers + user data + EDC/ECC */ (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3), /* subchannels P/Q */ 2); if (ret < 0) return (ret); scatter_secs(&trackdesc, bp, cnt); for (i = 0, p = bp+2352; i < cnt; i++) { #ifdef more_than_q_sub if ((p[15] & 0x80) != 0) printf("P"); #endif /* * As the drives don't return P-sub, we check * whether the index equals 0. */ qpto96((Uchar *)p, (Uchar *)p, p[2] == 0); p += 2448; } return (ret); } else { comerrno(EX_BAD, "Cannot fread_2448_16 on non MMC drives\n"); return (read_da(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC + all subch */ 0x02)); } } static int fread_2352(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt) { if (rp->ismmc) { return (read_cd(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC */ (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3), /* NO subchannels */ 0)); } else { comerrno(EX_BAD, "Cannot fread_2352 on non MMC drives\n"); return (read_da(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC + all subch */ 0x02)); } } static int fread_lin(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt) { if (addr != ULONG_C(0xF0000000)) addr = ULONG_C(0xFFFFFFFF); return (read_cd(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC */ (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3), /* plus all subchannels RAW */ 1)); } #endif /* CLONE_WRITE */ static int bits(int c) { int n = 0; if (c & 0x01) n++; if (c & 0x02) n++; if (c & 0x04) n++; if (c & 0x08) n++; if (c & 0x10) n++; if (c & 0x20) n++; if (c & 0x40) n++; if (c & 0x80) n++; return (n); } static int bitidx(int c) { if (c & 0x80) return (0); if (c & 0x40) return (1); if (c & 0x20) return (2); if (c & 0x10) return (3); if (c & 0x08) return (4); if (c & 0x04) return (5); if (c & 0x02) return (6); if (c & 0x01) return (7); return (-1); } static int fread_c2(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt) { if (rp->ismmc) { return (read_cd(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC + C2 */ /* (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 2 << 1),*/ (1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 1 << 1), /* without subchannels */ 0)); } else { return (read_da(usalp, bp, addr, cnt, rp->secsize, /* Sync + all headers + user data + EDC/ECC + C2 */ 0x04)); } } /* ARGSUSED */ static int fdata_null(rparm_t *rp, caddr_t bp, long addr, int cnt) { return (0); } static int fdata_c2(rparm_t *rp, caddr_t bp, long addr, int cnt) { int i; int j; int k; char *p; p = &bp[2352]; for (i = 0; i < cnt; i++, p += (2352+294)) { /* usal_prbytes("XXX ", p, 294);*/ if ((j = cmpbytes(p, zeroblk, 294)) < 294) { printf("C2 in sector: %3ld first at byte: %4d (0x%02X)", addr+i, j*8 + bitidx(p[j]), p[j]&0xFF); for (j = 0, k = 0; j < 294; j++) k += bits(p[j]); printf(" total: %4d errors\n", k); /* usal_prbytes("XXX ", p, 294);*/ rp->c2_errors += k; if (k > rp->c2_maxerrs) rp->c2_maxerrs = k; rp->c2_errsecs++; if (k >= 100) rp->c2_badsecs += 1; } } return (0); } #ifdef used static int read_scsi_g1(SCSI *usalp, caddr_t bp, long addr, int cnt) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = bp; /* scmd->size = cnt*512;*/ scmd->size = cnt*usalp->cap->c_bsize; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x28; scmd->cdb.g1_cdb.lun = usal_lun(usalp); g1_cdbaddr(&scmd->cdb.g1_cdb, addr); g1_cdblen(&scmd->cdb.g1_cdb, cnt); usalp->cmdname = "read extended"; return (usal_cmd(usalp)); } #endif #define G0_MAXADDR 0x1FFFFFL int write_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt) { if (addr <= G0_MAXADDR) return (write_g0(usalp, bp, addr, cnt)); else return (write_g1(usalp, bp, addr, cnt)); } int write_g0(SCSI *usalp, caddr_t bp, long addr, int cnt) { register struct usal_cmd *scmd = usalp->scmd; if (usalp->cap->c_bsize <= 0) raisecond("capacity_not_set", 0L); fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = bp; scmd->size = cnt*usalp->cap->c_bsize; scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G0_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g0_cdb.cmd = SC_WRITE; scmd->cdb.g0_cdb.lun = usal_lun(usalp); g0_cdbaddr(&scmd->cdb.g0_cdb, addr); scmd->cdb.g0_cdb.count = (Uchar)cnt; usalp->cmdname = "write_g0"; return (usal_cmd(usalp)); } int write_g1(SCSI *usalp, caddr_t bp, long addr, int cnt) { register struct usal_cmd *scmd = usalp->scmd; if (usalp->cap->c_bsize <= 0) raisecond("capacity_not_set", 0L); fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = bp; scmd->size = cnt*usalp->cap->c_bsize; scmd->flags = SCG_DISRE_ENA; scmd->cdb_len = SC_G1_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = SC_EWRITE; scmd->cdb.g1_cdb.lun = usal_lun(usalp); g1_cdbaddr(&scmd->cdb.g1_cdb, addr); g1_cdblen(&scmd->cdb.g1_cdb, cnt); usalp->cmdname = "write_g1"; return (usal_cmd(usalp)); } #ifdef used static void Xrequest_sense(SCSI *usalp) { char sense_buf[32]; struct usal_cmd ocmd; int sense_count; char *cmdsave; register struct usal_cmd *scmd = usalp->scmd; cmdsave = usalp->cmdname; movebytes(scmd, &ocmd, sizeof (*scmd)); fillbytes((caddr_t)sense_buf, sizeof (sense_buf), '\0'); fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = (caddr_t)sense_buf; scmd->size = sizeof (sense_buf); scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G0_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g1_cdb.cmd = 0x3; scmd->cdb.g1_cdb.lun = usal_lun(usalp); scmd->cdb.g0_cdb.count = sizeof (sense_buf); usalp->cmdname = "request sense"; usal_cmd(usalp); sense_count = sizeof (sense_buf) - usal_getresid(usalp); movebytes(&ocmd, scmd, sizeof (*scmd)); scmd->sense_count = sense_count; movebytes(sense_buf, (Uchar *)&scmd->sense, scmd->sense_count); usalp->cmdname = cmdsave; usal_printerr(usalp); usal_printresult(usalp); /* XXX restore key/code in future */ } #endif static int read_retry(SCSI *usalp, caddr_t bp, long addr, long cnt, int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt), rparm_t *rp) { /* int secsize = usalp->cap->c_bsize;*/ int secsize = rp->secsize; int try = 0; int err; char dummybuf[8192]; if (secsize > sizeof (dummybuf)) { errmsgno(EX_BAD, "Cannot retry, sector size %d too big.\n", secsize); return (-1); } errmsgno(EX_BAD, "Retrying from sector %ld.\n", addr); while (cnt > 0) { fprintf(stderr, "."); do { if (didintr) comexit(exsig); /* XXX besseres Konzept?!*/ wait_unit_ready(usalp, 120); if (try >= 10) { /* First 10 retries without seek */ if ((try % 8) == 0) { fprintf(stderr, "+"); /* Read last sector */ usalp->silent++; (*rfunc)(usalp, rp, dummybuf, usalp->cap->c_baddr, 1); usalp->silent--; } else if ((try % 4) == 0) { fprintf(stderr, "-"); /* Read first sector */ usalp->silent++; (*rfunc)(usalp, rp, dummybuf, 0, 1); usalp->silent--; } else { fprintf(stderr, "~"); /* Read random sector */ usalp->silent++; (*rfunc)(usalp, rp, dummybuf, choice(usalp->cap->c_baddr), 1); usalp->silent--; } if (didintr) comexit(exsig); /* XXX besseres Konzept?!*/ wait_unit_ready(usalp, 120); } if (didintr) comexit(exsig); /* XXX besseres Konzept?!*/ fillbytes(bp, secsize, 0); usalp->silent++; err = (*rfunc)(usalp, rp, bp, addr, 1); usalp->silent--; if (err < 0) { err = usalp->scmd->ux_errno; /* fprintf(stderr, "\n");*/ /* errmsgno(err, "Cannot read source disk\n");*/ } else { if (usal_getresid(usalp)) { fprintf(stderr, "\nresid: %d\n", usal_getresid(usalp)); return (-1); } break; } } while (++try < retries); if (try >= retries) { fprintf(stderr, "\n"); errmsgno(err, "Error on sector %ld not corrected. Total of %d errors.\n", addr, ++rp->errors); if (usalp->silent <= 1 && lverbose > 0) usal_printerr(usalp); add_bad(addr); if (!noerror) return (-1); errmsgno(EX_BAD, "-noerror set, continuing ...\n"); } else { if (try >= maxtry) maxtry = try; if (try > 1) { fprintf(stderr, "\n"); errmsgno(EX_BAD, "Error on sector %ld corrected after %d tries. Total of %d errors.\n", addr, try, rp->errors); } } try = 0; cnt -= 1; addr += 1; bp += secsize; } return (0); } static void read_generic(SCSI *usalp, parm_t *parmp, int (*rfunc)(SCSI *usalp, rparm_t *rp, caddr_t bp, long addr, int cnt), rparm_t *rp, int (*dfunc)(rparm_t *rp, caddr_t bp, long addr, int cnt)) { char filename[512]; char *defname = NULL; FILE *f; long addr = 0L; long old_addr = 0L; long num; long end = 0L; long start = 0L; long cnt = 0L; long next_point = 0L; long secs_per_point = 0L; double speed; int msec; int old_msec = 0; int err = 0; BOOL askrange = FALSE; BOOL isrange = FALSE; int secsize = rp->secsize; int i = 0; if (is_suid) { if (usalp->inq->type != INQ_ROMD) comerrno(EX_BAD, "Not root. Will only read from CD in suid/priv mode\n"); } if (parmp == NULL || parmp->askrange) askrange = TRUE; if (parmp != NULL && !askrange && (parmp->start <= parmp->end)) isrange = TRUE; filename[0] = '\0'; usalp->silent++; if (read_capacity(usalp) >= 0) end = usalp->cap->c_baddr + 1; usalp->silent--; if ((end <= 0 && isrange) || (askrange && usal_yes("Ignore disk size? "))) end = 10000000; /* Hack to read empty (e.g. blank=fast) disks */ if (parmp) { if (parmp->name) defname = parmp->name; if (defname != NULL) { fprintf(stderr, "Copy from SCSI (%d,%d,%d) disk to file '%s'\n", usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp), defname); } addr = start = parmp->start; if (parmp->end != -1 && parmp->end < end) end = parmp->end; cnt = Sbufsize / secsize; } if (defname == NULL) { defname = "disk.out"; fprintf(stderr, "Copy from SCSI (%d,%d,%d) disk to file\n", usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); fprintf(stderr, "Enter filename [%s]: ", defname); flush(); (void) rols_getline(filename, sizeof (filename)); } if (askrange) { addr = start; getlong("Enter starting sector for copy:", &addr, start, end-1); /* getlong("Enter starting sector for copy:", &addr, -300, end-1);*/ start = addr; } if (askrange) { num = end - addr; getlong("Enter number of sectors to copy:", &num, 1L, num); end = addr + num; } if (askrange) { /* XXX askcnt */ cnt = Sbufsize / secsize; getlong("Enter number of sectors per copy:", &cnt, 1L, cnt); } if (filename[0] == '\0') strncpy(filename, defname, sizeof (filename)); filename[sizeof (filename)-1] = '\0'; if (streql(filename, "-")) { f = stdout; #ifdef NEED_O_BINARY setmode(STDOUT_FILENO, O_BINARY); #endif } else if ((f = fileopen(filename, notrunc?"wcub":"wctub")) == NULL) comerr("Cannot open '%s'.\n", filename); fprintf(stderr, "end: %8ld\n", end); if (gettimeofday(&starttime, (struct timezone *)0) < 0) comerr("Cannot get start time\n"); if (meshpoints > 0) { if ((end-start) < meshpoints) secs_per_point = 1; else secs_per_point = (end-start) / meshpoints; next_point = start + secs_per_point; old_addr = start; } for (; addr < end; addr += cnt) { if (didintr) comexit(exsig); /* XXX besseres Konzept?!*/ if ((addr + cnt) > end) cnt = end - addr; if (meshpoints > 0) { if (addr > next_point) { msec = prstats_silent(); if ((msec - old_msec) == 0) /* Avoid division by zero */ msec = old_msec + 1; speed = ((addr - old_addr)/(1000.0/secsize)) / (0.001*(msec - old_msec)); if (do_factor) { if (is_cdrom) speed /= 176.400; else if (is_dvd) speed /= 1385.0; } fprintf(stderr, "addr: %8ld cnt: %ld", addr, cnt); printf("%8ld %8.2f\n", addr, speed); fprintf(stderr, "\r"); next_point += secs_per_point; old_addr = addr; old_msec = msec; i++; if (meshpoints < 100) flush(); else if (i % (meshpoints/100) == 0) flush(); } } fprintf(stderr, "addr: %8ld cnt: %ld\r", addr, cnt); usalp->silent++; if ((*rfunc)(usalp, rp, Sbuf, addr, cnt) < 0) { usalp->silent--; err = usalp->scmd->ux_errno; if (quiet) { fprintf(stderr, "\n"); } else if (usalp->silent == 0) { usal_printerr(usalp); } errmsgno(err, "Cannot read source disk\n"); if (read_retry(usalp, Sbuf, addr, cnt, rfunc, rp) < 0) goto out; } else { usalp->silent--; if (usal_getresid(usalp)) { fprintf(stderr, "\nresid: %d\n", usal_getresid(usalp)); goto out; } } (*dfunc)(rp, Sbuf, addr, cnt); if (filewrite(f, Sbuf, cnt * secsize) < 0) { err = geterrno(); fprintf(stderr, "\n"); errmsgno(err, "Cannot write '%s'\n", filename); break; } } fprintf(stderr, "addr: %8ld", addr); out: fprintf(stderr, "\n"); msec = prstats(); if (msec == 0) /* Avoid division by zero */ msec = 1; #ifdef OOO fprintf(stderr, "Read %.2f kB at %.1f kB/sec.\n", (double)(addr - start)/(1024.0/usalp->cap->c_bsize), (double)((addr - start)/(1024.0/usalp->cap->c_bsize)) / (0.001*msec)); #else fprintf(stderr, "Read %.2f kB at %.1f kB/sec.\n", (double)(addr - start)/(1024.0/secsize), (double)((addr - start)/(1024.0/secsize)) / (0.001*msec)); #endif print_bad(); } static void write_disk(SCSI *usalp, parm_t *parmp) { char filename[512]; char *defname = "disk.out"; FILE *f; long addr = 0L; long cnt; long amt; long end; int msec; int start; if (is_suid) comerrno(EX_BAD, "Not root. Will not write in suid/priv mode\n"); filename[0] = '\0'; if (read_capacity(usalp) >= 0) { end = usalp->cap->c_baddr + 1; print_capacity(usalp, stderr); } if (end <= 1) end = 10000000; /* Hack to write empty disks */ if (parmp) { if (parmp->name) defname = parmp->name; fprintf(stderr, "Copy from file '%s' to SCSI (%d,%d,%d) disk\n", defname, usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); addr = start = parmp->start; if (parmp->end != -1 && parmp->end < end) end = parmp->end; cnt = Sbufsize / usalp->cap->c_bsize; } else { fprintf(stderr, "Copy from file to SCSI (%d,%d,%d) disk\n", usal_scsibus(usalp), usal_target(usalp), usal_lun(usalp)); fprintf(stderr, "Enter filename [%s]: ", defname); flush(); (void) rols_getline(filename, sizeof (filename)); fprintf(stderr, "Notice: reading from file always starts at file offset 0.\n"); getlong("Enter starting sector for copy:", &addr, 0L, end-1); start = addr; cnt = end - addr; getlong("Enter number of sectors to copy:", &end, 1L, end); end = addr + cnt; cnt = Sbufsize / usalp->cap->c_bsize; getlong("Enter number of sectors per copy:", &cnt, 1L, cnt); /* fprintf(stderr, "end: %8ld\n", end);*/ } if (filename[0] == '\0') strncpy(filename, defname, sizeof (filename)); filename[sizeof (filename)-1] = '\0'; if (streql(filename, "-")) { f = stdin; #ifdef NEED_O_BINARY setmode(STDIN_FILENO, O_BINARY); #endif } else if ((f = fileopen(filename, "rub")) == NULL) comerr("Cannot open '%s'.\n", filename); fprintf(stderr, "end: %8ld\n", end); if (gettimeofday(&starttime, (struct timezone *)0) < 0) comerr("Cannot get start time\n"); for (; addr < end; addr += cnt) { if (didintr) comexit(exsig); /* XXX besseres Konzept?!*/ if ((addr + cnt) > end) cnt = end - addr; fprintf(stderr, "addr: %8ld cnt: %ld\r", addr, cnt); if ((amt = fileread(f, Sbuf, cnt * usalp->cap->c_bsize)) < 0) comerr("Cannot read '%s'\n", filename); if (amt == 0) break; if ((amt / usalp->cap->c_bsize) < cnt) cnt = amt / usalp->cap->c_bsize; if (write_scsi(usalp, Sbuf, addr, cnt) < 0) comerrno(usalp->scmd->ux_errno, "Cannot write destination disk\n"); } fprintf(stderr, "addr: %8ld\n", addr); msec = prstats(); if (msec == 0) /* Avoid division by zero */ msec = 1; fprintf(stderr, "Wrote %.2f kB at %.1f kB/sec.\n", (double)(addr - start)/(1024.0/usalp->cap->c_bsize), (double)((addr - start)/(1024.0/usalp->cap->c_bsize)) / (0.001*msec)); } static int choice(int n) { #if defined(HAVE_DRAND48) extern double drand48(void); return (drand48() * n); #else # if defined(HAVE_RAND) extern int rand(void); return (rand() % n); # else return (0); # endif #endif } static void ra(SCSI *usalp) { /* char filename[512];*/ FILE *f; /* long addr = 0L;*/ /* long cnt;*/ /* long end;*/ /* int msec;*/ /* int start;*/ /* int err = 0;*/ select_secsize(usalp, 2352); read_capacity(usalp); print_capacity(usalp, stderr); fillbytes(Sbuf, 50*2352, 0); if (read_g1(usalp, Sbuf, 0, 50) < 0) errmsg("read CD\n"); f = fileopen("DDA", "wctb"); /* filewrite(f, Sbuf, 50 * 2352 - usal_getresid(usalp));*/ filewrite(f, Sbuf, 50 * 2352); fclose(f); } #define g5x_cdblen(cdb, len) ((cdb)->count[0] = ((len) >> 16L)& 0xFF,\ (cdb)->count[1] = ((len) >> 8L) & 0xFF,\ (cdb)->count[2] = (len) & 0xFF) int read_da(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, int subcode) { register struct usal_cmd *scmd = usalp->scmd; if (usalp->cap->c_bsize <= 0) raisecond("capacity_not_set", 0L); fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = bp; scmd->size = cnt*framesize; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xd8; scmd->cdb.g5_cdb.lun = usal_lun(usalp); g5_cdbaddr(&scmd->cdb.g5_cdb, addr); g5_cdblen(&scmd->cdb.g5_cdb, cnt); scmd->cdb.g5_cdb.res10 = subcode; usalp->cmdname = "read_da"; return (usal_cmd(usalp)); } int read_cd(SCSI *usalp, caddr_t bp, long addr, int cnt, int framesize, int data, int subch) { register struct usal_cmd *scmd = usalp->scmd; fillbytes((caddr_t)scmd, sizeof (*scmd), '\0'); scmd->addr = bp; scmd->size = cnt*framesize; scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd->cdb_len = SC_G5_CDBLEN; scmd->sense_len = CCS_SENSE_LEN; scmd->cdb.g5_cdb.cmd = 0xBE; scmd->cdb.g5_cdb.lun = usal_lun(usalp); scmd->cdb.g5_cdb.res = 0; /* expected sector type field ALL */ g5_cdbaddr(&scmd->cdb.g5_cdb, addr); g5x_cdblen(&scmd->cdb.g5_cdb, cnt); scmd->cdb.g5_cdb.count[3] = data & 0xFF; scmd->cdb.g5_cdb.res10 = subch & 0x07; usalp->cmdname = "read_cd"; return (usal_cmd(usalp)); } static void oldmode(SCSI *usalp, int *errp, int *retrp) { Uchar mode[0x100]; Uchar cmode[0x100]; Uchar *p; int i; int len; fillbytes(mode, sizeof (mode), '\0'); fillbytes(cmode, sizeof (cmode), '\0'); if (!get_mode_params(usalp, 0x01, "CD error recovery parameter", mode, (Uchar *)0, (Uchar *)cmode, (Uchar *)0, &len)) { return; } if (xdebug) usal_prbytes("Mode Sense Data", mode, len); mode[0] = 0; mode[2] = 0; /* ??? ist manchmal 0x80 */ p = mode; p += mode[3] + 4; *p &= 0x3F; if (xdebug) usal_prbytes("Mode page 1:", p, 0x10); i = p[2]; if (errp != NULL) *errp = i; i = p[3]; if (retrp != NULL) *retrp = i; } static void domode(SCSI *usalp, int err, int retr) { Uchar mode[0x100]; Uchar cmode[0x100]; Uchar *p; int i; int len; fillbytes(mode, sizeof (mode), '\0'); fillbytes(cmode, sizeof (cmode), '\0'); if (!get_mode_params(usalp, 0x01, "CD error recovery parameter", mode, (Uchar *)0, (Uchar *)cmode, (Uchar *)0, &len)) { return; } if (xdebug || (err == -1 && retr == -1)) { usal_prbytes("Mode Sense Data", mode, len); } mode[0] = 0; mode[2] = 0; /* ??? ist manchmal 0x80 */ p = mode; p += mode[3] + 4; *p &= 0x3F; if (xdebug || (err == -1 && retr == -1)) usal_prbytes("Mode page 1:", p, 0x10); i = p[2]; if (err == -1) { getint("Error handling? ", &i, 0, 255); p[2] = i; } else { if (xdebug) fprintf(stderr, "Error handling set from %02X to %02X\n", p[2], err); p[2] = err; } i = p[3]; if (retr == -1) { getint("Retry count? ", &i, 0, 255); p[3] = i; } else { if (xdebug) fprintf(stderr, "Retry count set from %d to %d\n", p[3] & 0xFF, retr); p[3] = retr; } if (xdebug || (err == -1 && retr == -1)) usal_prbytes("Mode Select Data", mode, len); mode_select(usalp, mode, len, 0, usalp->inq->data_format >= 2); } /*--------------------------------------------------------------------------*/ static void qpto96(Uchar *sub, Uchar *subq, int dop); /*EXPORT void qpto96 __PR((Uchar *sub, Uchar *subq, int dop));*/ /* * Q-Sub auf 96 Bytes blähen und P-Sub addieren * * OUT: sub, IN: subqptr */ static void /*EXPORT void*/ qpto96(Uchar *sub, Uchar *subqptr, int dop) { Uchar tmp[16]; Uchar *p; int c; int i; if (subqptr == sub) { movebytes(subqptr, tmp, 12); subqptr = tmp; } fillbytes(sub, 96, '\0'); /* CSTYLED */ if (dop) for (i = 0, p = sub; i < 96; i++) { *p++ |= 0x80; } for (i = 0, p = sub; i < 12; i++) { c = subqptr[i] & 0xFF; /*printf("%02X\n", c);*/ if (c & 0x80) *p++ |= 0x40; else p++; if (c & 0x40) *p++ |= 0x40; else p++; if (c & 0x20) *p++ |= 0x40; else p++; if (c & 0x10) *p++ |= 0x40; else p++; if (c & 0x08) *p++ |= 0x40; else p++; if (c & 0x04) *p++ |= 0x40; else p++; if (c & 0x02) *p++ |= 0x40; else p++; if (c & 0x01) *p++ |= 0x40; else p++; } } /*--------------------------------------------------------------------------*/ static void ovtime(SCSI *usalp) { register int i; usalp->silent++; (void) test_unit_ready(usalp); usalp->silent--; if (test_unit_ready(usalp) < 0) return; printf("Doing 1000 'TEST UNIT READY' operations.\n"); if (gettimeofday(&starttime, (struct timezone *)0) < 0) comerr("Cannot get start time\n"); for (i = 1000; --i >= 0; ) { (void) test_unit_ready(usalp); if (didintr) return; } prstats(); /* * ATAPI drives do not like seek_g0() */ usalp->silent++; i = seek_g0(usalp, 0L); usalp->silent--; if (i >= 0) { printf("Doing 1000 'SEEK_G0 (0)' operations.\n"); if (gettimeofday(&starttime, (struct timezone *)0) < 0) comerr("Cannot get start time\n"); for (i = 1000; --i >= 0; ) { (void) seek_g0(usalp, 0L); if (didintr) return; } prstats(); } usalp->silent++; i = seek_g1(usalp, 0L); usalp->silent--; if (i < 0) return; printf("Doing 1000 'SEEK_G1 (0)' operations.\n"); if (gettimeofday(&starttime, (struct timezone *)0) < 0) comerr("Cannot get start time\n"); for (i = 1000; --i >= 0; ) { (void) seek_g1(usalp, 0L); if (didintr) return; } prstats(); } #define BAD_INC 16 long *badsecs; int nbad; int maxbad; static void add_bad(long addr) { if (maxbad == 0) { maxbad = BAD_INC; badsecs = malloc(maxbad * sizeof (long)); if (badsecs == NULL) comerr("No memory for bad sector list\n."); } if (nbad >= maxbad) { maxbad += BAD_INC; badsecs = realloc(badsecs, maxbad * sizeof (long)); if (badsecs == NULL) comerr("No memory to grow bad sector list\n."); } badsecs[nbad++] = addr; } static void print_bad(void) { int i; if (nbad == 0) return; fprintf(stderr, "Max corected retry count was %d (limited to %d).\n", maxtry, retries); fprintf(stderr, "The following %d sector(s) could not be read correctly:\n", nbad); for (i = 0; i < nbad; i++) fprintf(stderr, "%ld\n", badsecs[i]); }