1 /* @(#)readcd.c	1.129 19/04/11 Copyright 1987, 1995-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)readcd.c	1.129 19/04/11 Copyright 1987, 1995-2018 J. Schilling";
6 #endif
7 /*
8  *	Skeleton for the use of the scg genearal SCSI - driver
9  *
10  *	Copyright (c) 1987, 1995-2018 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/mconfig.h>
27 #include <schily/stdio.h>
28 #include <schily/standard.h>
29 #include <schily/unistd.h>
30 #include <schily/stdlib.h>
31 #include <schily/string.h>
32 #include <schily/fcntl.h>
33 #include <schily/time.h>
34 #include <schily/errno.h>
35 #include <schily/signal.h>
36 #include <schily/schily.h>
37 #include <schily/nlsdefs.h>
38 #include <schily/priv.h>
39 #include <schily/io.h>				/* for setmode() prototype */
40 
41 #include <scg/scgcmd.h>
42 #include <scg/scsireg.h>
43 #include <scg/scsitransp.h>
44 
45 #include "scsi_scan.h"
46 #include "scsimmc.h"
47 #define	qpto96	__nothing__
48 #include "cdrecord.h"
49 #include "cdrdeflt.h"
50 #undef	qpto96
51 #include "movesect.h"
52 
53 #include <ecc.h>
54 #include <edc.h>
55 #include "version.h"
56 
57 char	cdr_version[] = VERSION;
58 
59 #if	defined(PROTOTYPES)
60 #define	UINT_C(a)	(a##u)
61 #define	ULONG_C(a)	(a##ul)
62 #define	USHORT_C(a)	(a##uh)
63 #define	CONCAT(a, b)	a##b
64 #else
65 #define	UINT_C(a)	((unsigned)(a))
66 #define	ULONG_C(a)	((unsigned long)(a))
67 #define	USHORT_C(a)	((unsigned short)(a))
68 /* CSTYLED */
69 #define	CONCAT(a, b)	a/**/b
70 #endif
71 
72 extern	BOOL	getlong		__PR((char *, long *, long, long));
73 extern	BOOL	getint		__PR((char *, int *, int, int));
74 
75 typedef struct {
76 	long	start;
77 	long	end;
78 	long	sptr;		/* sectors per transfer */
79 	BOOL	askrange;
80 	char	*name;
81 } parm_t;
82 
83 typedef struct {
84 	int	errors;
85 	int	c2_errors;
86 	int	c2_maxerrs;
87 	int	c2_errsecs;
88 	int	c2_badsecs;
89 	int	secsize;	/* The output sector size on the file    */
90 	int	isecsize;	/* The input sector size from the medium */
91 	BOOL	ismmc;
92 } rparm_t;
93 
94 typedef struct {
95 	int	c1_errors;
96 	int	c2_errors;
97 	int	cu_errors;
98 	int	pi_errors;
99 } cxerror_t;
100 
101 typedef int (*start_cx_func_t)	__PR((SCSI*));	/* initiates a scan */
102 typedef int (*end_cx_func_t)	__PR((SCSI*));	/* ends a scan */
103 typedef int (*one_interval_func_t) __PR((SCSI *, /* scans a certain range, */
104 				cxerror_t *,	/* should be 75 sectors. */
105 				long, void *));	/* Return value is the next */
106 						/* sector to be scanned */
107 /*
108  * Describes one set of functions needed to perform an cx scan.
109  */
110 typedef struct {
111 	start_cx_func_t		start_func;
112 	end_cx_func_t		end_func;
113 	one_interval_func_t	one_interval_func;
114 } cx_scan_procedure_t;
115 
116 LOCAL	BOOL	mmc_isplextor		__PR((SCSI* scgp));
117 LOCAL	int	plextor_init_cx_scan	__PR((SCSI* scgp));
118 LOCAL	int	plextor_init_pi8_scan	__PR((SCSI* scgp));
119 LOCAL	int	plextor_init_pif_scan	__PR((SCSI* scgp));
120 LOCAL	int	plextor_end_scan	__PR((SCSI* scgp));
121 LOCAL	int	plextor_read_cx_values	__PR((SCSI* scgp, cxerror_t *pe, BOOL dopi));
122 LOCAL	int	nec_init_cx_scan	__PR((SCSI* scgp));
123 LOCAL	int	nec_end_scan		__PR((SCSI* scgp));
124 LOCAL	int	nec_scan_one_interval	__PR((SCSI* scgp, cxerror_t *pe, long addr, void *p));
125 LOCAL	int	plextor_scan_one_interval __PR((SCSI* scgp, cxerror_t *pe, long addr, void *p));
126 LOCAL	int	plextor_scan_one_dvd_interval __PR((SCSI* scgp, cxerror_t *pe, long addr, void *p));
127 
128 
129 /*
130  * Currently, Plextor and NEC cx scanning is supported
131  */
132 cx_scan_procedure_t	cx_scan_procedures[] = {
133 		{   plextor_init_cx_scan,
134 		    plextor_end_scan,
135 		    plextor_scan_one_interval },
136 
137 		{   nec_init_cx_scan,
138 		    nec_end_scan,
139 		    nec_scan_one_interval },
140 
141 		{ NULL }
142 };
143 
144 struct exargs {
145 	SCSI	*scgp;
146 	int	old_secsize;
147 	int	flags;
148 	int	exflags;
149 	int	excode;
150 	char	oerr[3];
151 } exargs;
152 
153 EXPORT	BOOL	cvt_cyls	__PR((void));
154 EXPORT	BOOL	cvt_bcyls	__PR((void));
155 EXPORT	void	print_defect_list __PR((void));
156 LOCAL	void	usage		__PR((int ret));
157 EXPORT	int	main		__PR((int ac, char **av));
158 LOCAL	void	scg_openerr	__PR((char *errstr));
159 LOCAL	int	find_drive	__PR((SCSI *scgp, char *dev));
160 LOCAL	void	intr		__PR((int sig));
161 LOCAL	void	exscsi		__PR((int excode, void *arg));
162 #ifdef	__needed__
163 LOCAL	void	excdr		__PR((int excode, void *arg));
164 #endif
165 LOCAL	int	prstats		__PR((void));
166 LOCAL	int	prstats_silent	__PR((void));
167 LOCAL	void	dorw		__PR((SCSI *scgp, char *filename, char *sectors));
168 LOCAL	void	doit		__PR((SCSI *scgp));
169 LOCAL	void	read_disk	__PR((SCSI *scgp, parm_t *parmp));
170 #ifdef	CLONE_WRITE
171 LOCAL	void	readcd_disk	__PR((SCSI *scgp, parm_t *parmp));
172 LOCAL	void	read_lin	__PR((SCSI *scgp, parm_t *parmp));
173 LOCAL	int	read_secheader	__PR((SCSI *scgp, long addr));
174 LOCAL	int	read_ftoc	__PR((SCSI *scgp, parm_t *parmp, BOOL do_sectype));
175 LOCAL	void	read_sectypes	__PR((SCSI *scgp, FILE *f));
176 LOCAL	void	get_sectype	__PR((SCSI *scgp, long addr, char *st));
177 #endif
178 
179 LOCAL	void	readc2_disk	__PR((SCSI *scgp, parm_t *parmp));
180 LOCAL	void	readcx_disk	__PR((SCSI *scgp, parm_t *parmp));
181 LOCAL	void	readpi_disk	__PR((SCSI *scgp, parm_t *parmp));
182 LOCAL	int	fread_data	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
183 #ifdef	CLONE_WRITE
184 LOCAL	int	fread_2448	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
185 LOCAL	int	fread_2448_16	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
186 LOCAL	int	fread_2352	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
187 LOCAL	int	fread_2048	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
188 LOCAL	int	fread_lin	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
189 #endif
190 LOCAL	int	bits		__PR((int c));
191 LOCAL	int	bitidx		__PR((int c));
192 LOCAL	int	fread_c2	__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
193 
194 LOCAL	int	fdata_null	__PR((rparm_t *rp, caddr_t bp, long addr, int cnt));
195 LOCAL	int	fdata_c2	__PR((rparm_t *rp, caddr_t bp, long addr, int cnt));
196 
197 #ifdef	used
198 LOCAL	int read_scsi_g1	__PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
199 #endif
200 
201 EXPORT	int	write_scsi	__PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
202 EXPORT	int	write_g0	__PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
203 EXPORT	int	write_g1	__PR((SCSI *scgp, caddr_t bp, long addr, int cnt));
204 
205 #ifdef	used
206 LOCAL	void	Xrequest_sense	__PR((SCSI *scgp));
207 #endif
208 LOCAL	int	read_retry	__PR((SCSI *scgp, caddr_t bp, long addr, long cnt,
209 					int (*rfunc)(SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt),
210 					rparm_t *rp));
211 LOCAL	void	read_generic	__PR((SCSI *scgp, parm_t *parmp,
212 					int (*rfunc)(SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt),
213 					rparm_t *rp,
214 					int (*dfunc)(rparm_t *rp, caddr_t bp, long addr, int cnt)
215 ));
216 LOCAL	void	write_disk	__PR((SCSI *scgp, parm_t *parmp));
217 LOCAL	int	choice		__PR((int n));
218 LOCAL	void	ra		__PR((SCSI *scgp));
219 
220 EXPORT	int	read_da		__PR((SCSI *scgp, caddr_t bp, long addr, int cnt, int framesize, int subcode));
221 LOCAL	int	read_sectors	__PR((SCSI *scgp, void *p, long addr, int cnt));
222 LOCAL	int	read_dvd_sectors __PR((SCSI *scgp, void *p, long addr, int cnt));
223 EXPORT	int	read_cd		__PR((SCSI *scgp, caddr_t bp, long addr, int cnt, int framesize, int data, int subch));
224 
225 LOCAL	void	oldmode		__PR((SCSI *scgp, int *errp, int *retrp));
226 LOCAL	void	domode		__PR((SCSI *scgp, int err, int retr));
227 
228 LOCAL	void	qpto96		__PR((Uchar *sub, Uchar *subq, int dop));
229 LOCAL	void	ovtime		__PR((SCSI *scgp));
230 LOCAL	void	add_bad		__PR((long addr));
231 LOCAL	void	print_bad	__PR((void));
232 LOCAL	void	priv_warn	__PR((const char *what, const char *msg));
233 
234 struct timeval	starttime;
235 struct timeval	stoptime;
236 int	didintr;
237 int	exsig;
238 
239 char	*Sbuf;
240 long	Sbufsize = -1L;
241 int	spt = 0;
242 
243 /*#define	MAX_RETRY	32*/
244 #define	MAX_RETRY	128
245 
246 int	help;
247 int	xdebug;
248 int	lverbose;
249 int	quiet;
250 BOOL	is_suid;
251 BOOL	is_cdrom;
252 BOOL	is_dvd;
253 BOOL	is_bd;
254 BOOL	do_write;
255 BOOL	c2scan;
256 BOOL	cxscan;
257 BOOL	pi8scan;
258 BOOL	pifscan;
259 BOOL	plot;
260 BOOL	fulltoc;
261 BOOL	clone;
262 BOOL	edc_corr;
263 BOOL	noerror;
264 BOOL	nocorr;
265 BOOL	notrunc;
266 int	retries = MAX_RETRY;
267 int	maxtry = 0;
268 int	meshpoints;
269 BOOL	do_factor;
270 
271 struct	scsi_format_data fmt;
272 
cvt_cyls()273 /*XXX*/EXPORT	BOOL cvt_cyls() { return (FALSE); }
cvt_bcyls()274 /*XXX*/EXPORT	BOOL cvt_bcyls() { return (FALSE); }
print_defect_list()275 /*XXX*/EXPORT	void print_defect_list() {}
276 
277 LOCAL void
usage(ret)278 usage(ret)
279 	int	ret;
280 {
281 	error(_("Usage:\treadcd [options]\n"));
282 	error(_("Options:\n"));
283 	error(_("\t-version	print version information and exit\n"));
284 	error(_("\tdev=target	SCSI target to use\n"));
285 	error(_("\tscgopts=spec	SCSI options for libscg\n"));
286 	error(_("\tf=filename	Name of file to read/write\n"));
287 	error(_("\tsectors=range	Range of sectors to read/write\n"));
288 	error(_("\tspeed=#		set speed of drive (MMC only)\n"));
289 	error(_("\tts=#		set maximum transfer size for a single SCSI command\n"));
290 	error(_("\tspt=#		set maximum nuber of sectors for a single SCSI command\n"));
291 	error(_("\t-w		Switch to write mode\n"));
292 	error(_("\t-c2scan		Do a C2 error scan\n"));
293 	error(_("\t-cxscan		Do a C1/C2/CU scan (only available on a few drives)\n"));
294 	error(_("\t-pi8scan	Do a DVD pisum8 scan (only available on a few drives)\n"));
295 	error(_("\t-pifscan	Do a DVD pif scan (only available on a few drives)\n"));
296 	error(_("\t-plot		Print data suitable for gnuplot\n"));
297 #ifdef	CLONE_WRITE
298 	error(_("\t-fulltoc	Retrieve the full TOC\n"));
299 	error(_("\t-clone		Retrieve the full TOC and all data\n"));
300 	error(_("\t-edc-corr	Try to do user level Reed Solomon repair (experimental)\n"));
301 #endif
302 	error(_("\ttimeout=#	set the default SCSI command timeout to #.\n"));
303 	error(_("\tdebug=#,-d	Set to # or increment misc debug level\n"));
304 	error(_("\tkdebug=#,kd=#	do Kernel debugging\n"));
305 	error(_("\t-quiet,-q	be more quiet in error retry mode\n"));
306 	error(_("\t-verbose,-v	increment general verbose level by one\n"));
307 	error(_("\t-Verbose,-V	increment SCSI command transport verbose level by one\n"));
308 	error(_("\t-silent,-s	do not print status of failed SCSI commands\n"));
309 	error(_("\t-scanbus	scan the SCSI bus and exit\n"));
310 	error(_("\t-noerror	do not abort on error\n"));
311 #ifdef	CLONE_WRITE
312 	error(_("\t-nocorr		do not apply error correction in drive\n"));
313 #endif
314 	error(_("\t-notrunc	do not truncate outputfile in read mode\n"));
315 	error(_("\tretries=#	set retry count (default is %d)\n"), retries);
316 	error(_("\t-overhead	meter SCSI command overhead times\n"));
317 	error(_("\tmeshpoints=#	print read-speed at # locations\n"));
318 	error(_("\t-factor		try to use speed factor with meshpoints=# if possible\n"));
319 	error("\n");
320 	error(_("sectors=0-0 will read nothing, sectors=0-1 will read one sector starting from 0\n"));
321 	exit(ret);
322 }
323 
324 /* CSTYLED */
325 char	opts[]   = "debug#,d+,kdebug#,kd#,timeout#,quiet,q,verbose+,v+,Verbose+,V+,x+,xd#,silent,s,help,h,version,scanbus,dev*,scgopts*,sectors*,w,c2scan,cxscan,pi8scan,pifscan,plot,fulltoc,clone,edc-corr,noerror,nocorr,notrunc,retries#,factor,f*,speed#,ts&,spt#,overhead,meshpoints#";
326 
327 EXPORT int
main(ac,av)328 main(ac, av)
329 	int	ac;
330 	char	*av[];
331 {
332 	char	*dev = NULL;
333 	char	*scgopts = NULL;
334 	int	fcount;
335 	int	cac;
336 	char	* const *cav;
337 #if	defined(USE_NLS)
338 	char	*dir;
339 #endif
340 	int	scsibus	= -1;
341 	int	target	= -1;
342 	int	lun	= -1;
343 	int	silent	= 0;
344 	int	verbose	= 0;
345 	int	kdebug	= 0;
346 	int	debug	= 0;
347 	int	deftimeout = 40;
348 	int	pversion = 0;
349 	int	scanbus = 0;
350 	int	speed	= -1;
351 	int	dooverhead = 0;
352 	SCSI	*scgp;
353 	char	*filename = NULL;
354 	char	*sectors = NULL;
355 
356 #ifdef	HAVE_SOLARIS_PPRIV
357 	/*
358 	 * Try to gain additional privs on Solaris
359 	 */
360 	do_pfexec(ac, av,
361 		PRIV_FILE_DAC_READ,
362 		PRIV_SYS_DEVICES,
363 		PRIV_NET_PRIVADDR,
364 		NULL);
365 #endif
366 	save_args(ac, av);
367 
368 #if	defined(USE_NLS)
369 	(void) setlocale(LC_ALL, "");
370 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
371 #define	TEXT_DOMAIN "cdrecord"	/* Use this only if it weren't */
372 #endif
373 	dir = searchfileinpath("share/locale", F_OK,
374 					SIP_ANY_FILE|SIP_NO_PATH, NULL);
375 	if (dir)
376 		(void) bindtextdomain(TEXT_DOMAIN, dir);
377 	else
378 #if defined(PROTOTYPES) && defined(INS_BASE)
379 	(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
380 #else
381 	(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
382 #endif
383 	(void) textdomain(TEXT_DOMAIN);
384 #endif
385 
386 	cac = --ac;
387 	cav = ++av;
388 
389 	if (getallargs(&cac, &cav, opts,
390 			&debug, &debug,
391 			&kdebug, &kdebug,
392 			&deftimeout,
393 			&quiet, &quiet,
394 			&lverbose, &lverbose,
395 			&verbose, &verbose,
396 			&xdebug, &xdebug,
397 			&silent, &silent,
398 			&help, &help, &pversion,
399 			&scanbus, &dev, &scgopts, &sectors, &do_write,
400 			&c2scan, &cxscan, &pi8scan, &pifscan,
401 			&plot,
402 			&fulltoc, &clone,
403 			&edc_corr,
404 			&noerror, &nocorr,
405 			&notrunc, &retries, &do_factor, &filename,
406 			&speed, getnum, &Sbufsize, &spt,
407 			&dooverhead, &meshpoints) < 0) {
408 		errmsgno(EX_BAD, _("Bad flag: %s.\n"), cav[0]);
409 		usage(EX_BAD);
410 	}
411 	if (help)
412 		usage(0);
413 	if (pversion) {
414 		printf(_("readcd %s %s (%s-%s-%s) Copyright (C) 1987, 1995-2018 %s\n"),
415 								cdr_version, VERSION_DATE,
416 								HOST_CPU, HOST_VENDOR, HOST_OS,
417 								_("Joerg Schilling"));
418 		exit(0);
419 	}
420 
421 	fcount = 0;
422 	cac = ac;
423 	cav = av;
424 
425 	while (getfiles(&cac, &cav, opts) > 0) {
426 		fcount++;
427 		if (fcount == 1) {
428 			if (*astoi(cav[0], &target) != '\0') {
429 				errmsgno(EX_BAD,
430 					_("Target '%s' is not a Number.\n"),
431 								cav[0]);
432 				usage(EX_BAD);
433 				/* NOTREACHED */
434 			}
435 		}
436 		if (fcount == 2) {
437 			if (*astoi(cav[0], &lun) != '\0') {
438 				errmsgno(EX_BAD,
439 					_("Lun is '%s' not a Number.\n"),
440 								cav[0]);
441 				usage(EX_BAD);
442 				/* NOTREACHED */
443 			}
444 		}
445 		if (fcount == 3) {
446 			if (*astoi(cav[0], &scsibus) != '\0') {
447 				errmsgno(EX_BAD,
448 					_("Scsibus is '%s' not a Number.\n"),
449 								cav[0]);
450 				usage(EX_BAD);
451 				/* NOTREACHED */
452 			}
453 		}
454 		cac--;
455 		cav++;
456 	}
457 
458 	/*
459 	 * The following scg_open() call needs more privileges, so we check for
460 	 * sufficient privileges here.
461 	 * The check has been introduced as some Linux distributions miss the
462 	 * skills to perceive the necessity for the needed privileges. So we
463 	 * warn which features are impaired by actually missing privileges.
464 	 */
465 	if (!priv_eff_priv(SCHILY_PRIV_FILE_DAC_READ))
466 		priv_warn("file read", "You will not be able to open all needed devices.");
467 #ifndef	__SUNOS5
468 	/*
469 	 * Due to a design bug in the Solaris USCSI ioctl, we don't need
470 	 * PRIV_FILE_DAC_WRITE to send SCSI commands and most installations
471 	 * probably don't grant PRIV_FILE_DAC_WRITE. Once we need /dev/scg*,
472 	 * we would need to test for PRIV_FILE_DAC_WRITE also.
473 	 */
474 	if (!priv_eff_priv(SCHILY_PRIV_FILE_DAC_WRITE))
475 		priv_warn("file write", "You will not be able to open all needed devices.");
476 #endif
477 	if (!priv_eff_priv(SCHILY_PRIV_SYS_DEVICES))
478 		priv_warn("device",
479 		    "You may not be able to send all needed SCSI commands, this my cause various unexplainable problems.");
480 	if (!priv_eff_priv(SCHILY_PRIV_NET_PRIVADDR))
481 		priv_warn("network", "You will not be able to do remote SCSI.");
482 
483 /*error("dev: '%s'\n", dev);*/
484 	if (!scanbus)
485 		cdr_defaults(&dev, NULL, NULL, &Sbufsize, NULL);
486 	if (debug) {
487 		printf("dev: '%s'\n", dev);
488 	}
489 	if (dev || scanbus || (scsibus < 0 && target < 0 && lun < 0)) {
490 		char	errstr[80];
491 
492 		/*
493 		 * Call scg_remote() to force loading the remote SCSI transport
494 		 * library code that is located in librscg instead of the dummy
495 		 * remote routines that are located inside libscg.
496 		 */
497 		scg_remote();
498 		if (dev != NULL &&
499 		    ((strncmp(dev, "HELP", 4) == 0) ||
500 		    (strncmp(dev, "help", 4) == 0))) {
501 			scg_help(stderr);
502 			exit(0);
503 		}
504 		if ((scgp = scg_open(dev, errstr, sizeof (errstr), debug, lverbose)) == (SCSI *)0) {
505 			scg_openerr(errstr);
506 			/* NOTREACHED */
507 		}
508 		if (!scanbus && scg_scsibus(scgp) < 0 &&
509 				scg_target(scgp) < 0 && scg_lun(scgp) < 0) {
510 			int i = find_drive(scgp, dev);
511 
512 			if (i < 0) {
513 				scg_openerr("");
514 				/* NOTREACHED */
515 			}
516 		}
517 	} else {
518 		if (scsibus == -1 && target >= 0 && lun >= 0)
519 			scsibus = 0;
520 
521 		scgp = scg_smalloc();
522 		scgp->debug = debug;
523 		scgp->kdebug = kdebug;
524 
525 		scg_settarget(scgp, scsibus, target, lun);
526 		if (scg__open(scgp, NULL) <= 0)
527 			comerr(_("Cannot open SCSI driver.\n"));
528 	}
529 	if (scgopts) {
530 		int	i = scg_opts(scgp, scgopts);
531 		if (i <= 0)
532 			exit(i < 0 ? EX_BAD : 0);
533 	}
534 	scgp->silent = silent;
535 	scgp->verbose = verbose;
536 	scgp->debug = debug;
537 	scgp->kdebug = kdebug;
538 	scg_settimeout(scgp, deftimeout);
539 
540 	if (Sbufsize < 0)
541 		Sbufsize = 256*1024L;
542 	Sbufsize = scg_bufsize(scgp, Sbufsize);
543 	if ((Sbuf = scg_getbuf(scgp, Sbufsize)) == NULL)
544 		comerr(_("Cannot get SCSI I/O buffer.\n"));
545 
546 	/*
547 	 * Did we get our privs from suid?
548 	 */
549 	is_suid = priv_from_priv();
550 	/*
551 	 * This is only for OS that do not support fine grained privs.
552 	 */
553 	if (!is_suid) {
554 #ifdef	HAVE_ISSETUGID
555 		is_suid = issetugid();
556 #else
557 		is_suid = geteuid() != getuid();
558 #endif
559 	}
560 	/*
561 	 * Drop privs we do not need anymore.
562 	 * We no longer need:
563 	 *	file_dac_read,net_privaddr
564 	 * We still need:
565 	 *	sys_devices
566 	 */
567 	if (is_suid || getuid() != 0)
568 		priv_drop();
569 	/*
570 	 * We don't need root privilleges anymore.
571 	 */
572 #ifdef	HAVE_SETREUID
573 	if (setreuid(-1, getuid()) < 0)
574 #else
575 #ifdef	HAVE_SETEUID
576 	if (seteuid(getuid()) < 0)
577 #else
578 	if (setuid(getuid()) < 0)
579 #endif
580 #endif
581 		comerr(_("Panic cannot set back effective uid.\n"));
582 
583 	/* code to use SCG */
584 
585 	if (scanbus) {
586 		int	i = select_target(scgp, stdout);
587 
588 		if (i < 0) {
589 			scg_openerr("");
590 			/* NOTREACHED */
591 		}
592 		exit(0);
593 	}
594 	seterrno(0);
595 	if (!do_inquiry(scgp, FALSE)) {
596 		int	err = geterrno();
597 
598 		if (err == EPERM || err == EACCES) {
599 			scg_openerr("");
600 			/* NOTREACHED */
601 		}
602 	}
603 	allow_atapi(scgp, TRUE);    /* Try to switch to 10 byte mode cmds */
604 	if (is_mmc(scgp, NULL, NULL)) {
605 		int	rspeed;
606 		int	wspeed;
607 		/*
608 		 * At this point we know that we have a SCSI-3/mmc compliant drive.
609 		 * Unfortunately ATAPI drives violate the SCSI spec in returning
610 		 * a response data format of '1' which from the SCSI spec would
611 		 * tell us not to use the "PF" bit in mode select. As ATAPI drives
612 		 * require the "PF" bit to be set, we 'correct' the inquiry data.
613 		 */
614 		if (scgp->inq->data_format < 2)
615 			scgp->inq->data_format = 2;
616 
617 		if ((rspeed = get_curprofile(scgp)) >= 0) {
618 			if (rspeed >= 0x08 && rspeed < 0x10)
619 				is_cdrom = TRUE;
620 			if (rspeed >= 0x10 && rspeed < 0x20)
621 				is_dvd = TRUE;
622 			if (rspeed >= 0x40 && rspeed < 0x50)
623 				is_bd = TRUE;
624 		} else {
625 			BOOL	dvd;
626 
627 			mmc_check(scgp, NULL, NULL, NULL, NULL, &dvd, NULL);
628 			if (dvd == FALSE) {
629 				is_cdrom = TRUE;
630 			} else {
631 				char	xb[32];
632 
633 				if (read_dvd_structure(scgp, (caddr_t)xb, 32, 0, 0, 0, 0) >= 0) {
634 				/*
635 				 * If read DVD structure is supported and works, then
636 				 * we must have a DVD media in the drive. Signal to
637 				 * use the DVD driver.
638 				 */
639 					is_dvd = TRUE;
640 				} else {
641 					is_cdrom = TRUE;
642 				}
643 			}
644 		}
645 
646 		if (speed > 0)
647 			speed *= 177;
648 		if (speed > 0xFFFF || speed < 0)
649 			speed = 0xFFFF;
650 		scsi_set_speed(scgp, speed, speed, ROTCTL_CLV);
651 		if (scsi_get_speed(scgp, &rspeed, &wspeed) >= 0) {
652 			error(_("Read  speed: %5d kB/s (CD %3dx, DVD %2dx, BD %2dx).\n"),
653 				rspeed, rspeed/176, rspeed/1385, rspeed/4495);
654 			error(_("Write speed: %5d kB/s (CD %3dx, DVD %2dx, BD %2dx).\n"),
655 				wspeed, wspeed/176, wspeed/1385, wspeed/4495);
656 		}
657 	}
658 	exargs.scgp	   = scgp;
659 	exargs.old_secsize = -1;
660 /*	exargs.flags	   = flags;*/
661 	exargs.exflags	   = 0;
662 	exargs.excode	   = 0;
663 	exargs.oerr[2]	   = 0;
664 
665 	/*
666 	 * Install exit handler before we change the drive status.
667 	 */
668 	on_comerr(exscsi, &exargs);
669 	signal(SIGINT, intr);
670 	signal(SIGTERM, intr);
671 
672 	if (dooverhead) {
673 		ovtime(scgp);
674 		comexit(0);
675 	}
676 
677 	if (is_suid) {
678 		if (scgp->inq->type != INQ_ROMD)
679 			comerrno(EX_BAD, _("Not root. Will only work on CD-ROM in suid/priv mode\n"));
680 	}
681 
682 	if (filename || sectors || c2scan || cxscan || pi8scan || pifscan ||
683 	    meshpoints || fulltoc ||
684 	    clone || edc_corr) {
685 		dorw(scgp, filename, sectors);
686 	} else {
687 		doit(scgp);
688 	}
689 	comexit(exargs.excode);
690 	return (exargs.excode);
691 }
692 
693 LOCAL void
scg_openerr(errstr)694 scg_openerr(errstr)
695 	char	*errstr;
696 {
697 	int	err = geterrno();
698 
699 	errmsgno(err, _("%s%sCannot open or use SCSI driver.\n"), errstr, errstr[0]?". ":"");
700 	errmsgno(EX_BAD, _("For possible targets try 'readcd -scanbus'.%s\n"),
701 				geteuid() ? _(" Make sure you are root."):"");
702 	errmsgno(EX_BAD, _("For possible transport specifiers try 'readcd dev=help'.\n"));
703 	exit(err);
704 }
705 
706 LOCAL int
find_drive(scgp,dev)707 find_drive(scgp, dev)
708 	SCSI	*scgp;
709 	char	*dev;
710 {
711 	int	ntarget;
712 
713 	error(_("No target specified, trying to find one...\n"));
714 	ntarget = find_target(scgp, INQ_ROMD, -1);
715 	if (ntarget < 0)
716 		return (ntarget);
717 	if (ntarget == 1) {
718 		/*
719 		 * Simple case, exactly one CD-ROM found.
720 		 */
721 		find_target(scgp, INQ_ROMD, 1);
722 	} else if (ntarget <= 0 && (ntarget = find_target(scgp, INQ_WORM, -1)) == 1) {
723 		/*
724 		 * Exactly one CD-ROM acting as WORM found.
725 		 */
726 		find_target(scgp, INQ_WORM, 1);
727 	} else if (ntarget <= 0) {
728 		/*
729 		 * No single CD-ROM or WORM found.
730 		 */
731 		errmsgno(EX_BAD, _("No CD/DVD/BD-Recorder target found.\n"));
732 		errmsgno(EX_BAD, _("Your platform may not allow to scan for SCSI devices.\n"));
733 		comerrno(EX_BAD, _("Call 'readcd dev=help' or ask your sysadmin for possible targets.\n"));
734 	} else {
735 		errmsgno(EX_BAD, _("Too many CD/DVD/BD-Recorder targets found.\n"));
736 		select_target(scgp, stdout);
737 		comerrno(EX_BAD, _("Select a target from the list above and use 'readcd dev=%s%sb,t,l'.\n"),
738 			dev?dev:"", dev?(dev[strlen(dev)-1] == ':'?"":":"):"");
739 	}
740 	error(_("Using dev=%s%s%d,%d,%d.\n"),
741 			dev?dev:"", dev?(dev[strlen(dev)-1] == ':'?"":":"):"",
742 			scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp));
743 	return (ntarget);
744 }
745 
746 /*
747  * XXX Leider kann man vim Signalhandler keine SCSI Kommandos verschicken
748  * XXX da meistens das letzte SCSI Kommando noch laeuft.
749  * XXX Eine Loesung waere ein Abort Callback in SCSI *.
750  */
751 LOCAL void
intr(sig)752 intr(sig)
753 	int	sig;
754 {
755 	didintr++;
756 	exsig = sig;
757 /*	comexit(sig);*/
758 }
759 
760 /* ARGSUSED */
761 LOCAL void
exscsi(excode,arg)762 exscsi(excode, arg)
763 	int	excode;
764 	void	*arg;
765 {
766 	struct exargs	*exp = (struct exargs *)arg;
767 		int	i;
768 
769 	/*
770 	 * Try to restore the old sector size.
771 	 */
772 	if (exp != NULL && exp->exflags == 0) {
773 		for (i = 0; i < 10*100; i++) {
774 			if (!exp->scgp->running)
775 				break;
776 			if (i == 10) {
777 				errmsgno(EX_BAD,
778 					_("Waiting for current SCSI command to finish.\n"));
779 			}
780 			usleep(100000);
781 		}
782 
783 		if (!exp->scgp->running) {
784 			if (exp->oerr[2] != 0) {
785 				domode(exp->scgp, exp->oerr[0], exp->oerr[1]);
786 			}
787 			if (exp->old_secsize > 0 && exp->old_secsize != 2048)
788 				select_secsize(exp->scgp, exp->old_secsize);
789 		}
790 		exp->exflags++;	/* Make sure that it only get called once */
791 	}
792 }
793 
794 #ifdef	__needed__
795 LOCAL void
excdr(excode,arg)796 excdr(excode, arg)
797 	int	excode;
798 	void	*arg;
799 {
800 	exscsi(excode, arg);
801 
802 #ifdef	needed
803 	/* Do several other restores/statistics here (see cdrecord.c) */
804 #endif
805 }
806 #endif
807 
808 /*
809  * Return milliseconds since start time.
810  */
811 LOCAL int
prstats()812 prstats()
813 {
814 	int	sec;
815 	int	usec;
816 	int	tmsec;
817 
818 	if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
819 		comerr(_("Cannot get time\n"));
820 
821 	sec = stoptime.tv_sec - starttime.tv_sec;
822 	usec = stoptime.tv_usec - starttime.tv_usec;
823 	tmsec = sec*1000 + usec/1000;
824 #ifdef	lint
825 	tmsec = tmsec;	/* Bisz spaeter */
826 #endif
827 	if (usec < 0) {
828 		sec--;
829 		usec += 1000000;
830 	}
831 
832 	error(_("Time total: %d.%03dsec\n"), sec, usec/1000);
833 	return (1000*sec + (usec / 1000));
834 }
835 
836 /*
837  * Return milliseconds since start time, but be silent this time.
838  */
839 LOCAL int
prstats_silent()840 prstats_silent()
841 {
842 	int	sec;
843 	int	usec;
844 	int	tmsec;
845 
846 	if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
847 		comerr(_("Cannot get time\n"));
848 
849 	sec = stoptime.tv_sec - starttime.tv_sec;
850 	usec = stoptime.tv_usec - starttime.tv_usec;
851 	tmsec = sec*1000 + usec/1000;
852 #ifdef	lint
853 	tmsec = tmsec;	/* Bisz spaeter */
854 #endif
855 	if (usec < 0) {
856 		sec--;
857 		usec += 1000000;
858 	}
859 
860 	return (1000*sec + (usec / 1000));
861 }
862 
863 LOCAL void
dorw(scgp,filename,sectors)864 dorw(scgp, filename, sectors)
865 	SCSI	*scgp;
866 	char	*filename;
867 	char	*sectors;
868 {
869 	parm_t	params;
870 	char	*p = NULL;
871 
872 	params.start = 0;
873 	params.end = -1;
874 	params.sptr = -1;
875 	params.askrange = FALSE;
876 	params.name = NULL;
877 
878 	if (filename)
879 		params.name = filename;
880 	if (meshpoints > 0) {
881 		if (params.name == NULL)
882 			params.name = "/dev/null";
883 	}
884 	if (sectors)
885 		p = astol(sectors, &params.start);
886 	if (p && *p == '-')
887 		p = astol(++p, &params.end);
888 	if (p && *p != '\0')
889 		comerrno(EX_BAD, _("Not a valid sector range '%s'\n"), sectors);
890 
891 	if (!wait_unit_ready(scgp, 60))
892 		comerrno(EX_BAD, _("Device not ready.\n"));
893 
894 #ifdef	CLONE_WRITE
895 	if (fulltoc) {
896 		if (params.name == NULL)
897 			params.name = "/dev/null";
898 		read_ftoc(scgp, &params, FALSE);
899 	} else if (clone || edc_corr) {
900 		if (!is_mmc(scgp, NULL, NULL))
901 			comerrno(EX_BAD, _("Unsupported device for clone mode.\n"));
902 		if (!edc_corr)
903 			noerror = TRUE;
904 		if (retries == MAX_RETRY)
905 			retries = 10;
906 		if (params.name == NULL)
907 			params.name = "/dev/null";
908 
909 		if (clone)
910 		if (read_ftoc(scgp, &params, TRUE) < 0)
911 			comerrno(EX_BAD, _("Read fulltoc problems.\n"));
912 		readcd_disk(scgp, &params);
913 	} else
914 #endif
915 	if (c2scan) {
916 		noerror = TRUE;
917 		if (retries == MAX_RETRY)
918 			retries = 10;
919 		if (params.name == NULL)
920 			params.name = "/dev/null";
921 		readc2_disk(scgp, &params);
922 	} else if (cxscan) {
923 		if (plot && lverbose == 0)
924 			lverbose = 1;
925 		noerror = TRUE;
926 		if (retries == MAX_RETRY)
927 			retries = 10;
928 		if (params.name == NULL)
929 			params.name = "/dev/null";
930 		readcx_disk(scgp, &params);
931 	} else if (pi8scan || pifscan) {
932 		if (plot && lverbose == 0)
933 			lverbose = 1;
934 		noerror = TRUE;
935 		if (retries == MAX_RETRY)
936 			retries = 10;
937 		if (params.name == NULL)
938 			params.name = "/dev/null";
939 		readpi_disk(scgp, &params);
940 	} else if (do_write)
941 		write_disk(scgp, &params);
942 	else
943 		read_disk(scgp, &params);
944 }
945 
946 LOCAL void
doit(scgp)947 doit(scgp)
948 	SCSI	*scgp;
949 {
950 	int	i = 0;
951 	parm_t	params;
952 
953 	params.start = 0;
954 	params.end = -1;
955 	params.sptr = -1;
956 	params.askrange = TRUE;
957 	params.name = "/dev/null";
958 
959 	for (;;) {
960 		if (!wait_unit_ready(scgp, 60))
961 			comerrno(EX_BAD, _("Device not ready.\n"));
962 
963 		printf(_("0:read 1:veri   2:erase   3:read buffer 4:cache 5:ovtime 6:cap\n"));
964 		printf(_("7:wne  8:floppy 9:verify 10:checkcmds  11:read disk 12:write disk\n"));
965 		printf(_("13:scsireset 14:seektest 15: readda 16: reada 17: c2err\n"));
966 #ifdef	CLONE_WRITE
967 		printf(_("18:readcd 19: lin 20: full toc\n"));
968 #endif
969 
970 		getint(_("Enter selection:"), &i, 0, 20);
971 		if (didintr)
972 			return;
973 
974 		switch (i) {
975 
976 		case 5:		ovtime(scgp);		break;
977 		case 11:	read_disk(scgp, 0);	break;
978 		case 12:	write_disk(scgp, 0);	break;
979 		case 15:	ra(scgp);		break;
980 /*		case 16:	reada_disk(scgp, 0, 0);	break;*/
981 		case 17:	readc2_disk(scgp, &params);	break;
982 #ifdef	CLONE_WRITE
983 		case 18:	readcd_disk(scgp, 0);	break;
984 		case 19:	read_lin(scgp, 0);	break;
985 		case 20:	read_ftoc(scgp, 0, FALSE);	break;
986 #endif
987 		}
988 	}
989 }
990 
991 LOCAL void
read_disk(scgp,parmp)992 read_disk(scgp, parmp)
993 	SCSI	*scgp;
994 	parm_t	*parmp;
995 {
996 	rparm_t	rp;
997 
998 	read_capacity(scgp);
999 	print_capacity(scgp, stderr);
1000 
1001 	rp.errors = 0;
1002 	rp.c2_errors = 0;
1003 	rp.c2_maxerrs = 0;
1004 	rp.c2_errsecs = 0;
1005 	rp.c2_badsecs = 0;
1006 	rp.isecsize = rp.secsize = scgp->cap->c_bsize;
1007 
1008 	read_generic(scgp, parmp, fread_data, &rp, fdata_null);
1009 }
1010 
1011 #ifdef	CLONE_WRITE
1012 LOCAL void
readcd_disk(scgp,parmp)1013 readcd_disk(scgp, parmp)
1014 	SCSI	*scgp;
1015 	parm_t	*parmp;
1016 {
1017 	rparm_t	rp;
1018 	int	osecsize = 2048;
1019 	int	oerr = 0;
1020 	int	oretr = 10;
1021 	int	(*funcp)__PR((SCSI *_scgp, rparm_t *_rp, caddr_t bp, long addr, int cnt));
1022 
1023 	scgp->silent++;
1024 	if (read_capacity(scgp) >= 0)
1025 		osecsize = scgp->cap->c_bsize;
1026 	scgp->silent--;
1027 	if (osecsize != 2048)
1028 		select_secsize(scgp, 2048);
1029 
1030 	read_capacity(scgp);
1031 	print_capacity(scgp, stderr);
1032 
1033 	rp.errors = 0;
1034 	rp.c2_errors = 0;
1035 	rp.c2_maxerrs = 0;
1036 	rp.c2_errsecs = 0;
1037 	rp.c2_badsecs = 0;
1038 	rp.isecsize = rp.secsize = 2448;
1039 	rp.ismmc = is_mmc(scgp, NULL, NULL);
1040 	funcp = fread_2448;
1041 
1042 	wait_unit_ready(scgp, 10);
1043 	if (fread_2448(scgp, &rp, Sbuf, 0, 0) < 0) {
1044 		errmsgno(EX_BAD, _("read 2448 failed\n"));
1045 		if (rp.ismmc &&
1046 		    fread_2448_16(scgp, &rp, Sbuf, 0, 0) >= 0) {
1047 			errmsgno(EX_BAD, _("read 2448_16 : OK\n"));
1048 
1049 			funcp = fread_2448_16;
1050 		}
1051 	}
1052 	if (edc_corr) {
1053 		funcp = fread_2048;
1054 		rp.secsize = 2048;	/* We ouput CD-ROM data sectors  */
1055 		rp.isecsize = 2352;	/* We read CD-DA sectors from CD */
1056 	}
1057 
1058 	oldmode(scgp, &oerr, &oretr);
1059 	exargs.oerr[0] = oerr;
1060 	exargs.oerr[1] = oretr;
1061 	exargs.oerr[2] = 0xFF;
1062 	if (parmp == NULL)		/* XXX Nur am Anfang!!! */
1063 		domode(scgp, -1, -1);
1064 	else
1065 		domode(scgp, nocorr?0x21:0x20, 10);
1066 
1067 	read_generic(scgp, parmp, funcp, &rp, fdata_null);
1068 	if (osecsize != 2048)
1069 		select_secsize(scgp, osecsize);
1070 	domode(scgp, oerr, oretr);
1071 }
1072 
1073 /* ARGSUSED */
1074 LOCAL void
read_lin(scgp,parmp)1075 read_lin(scgp, parmp)
1076 	SCSI	*scgp;
1077 	parm_t	*parmp;
1078 {
1079 	parm_t	parm;
1080 	rparm_t	rp;
1081 
1082 	read_capacity(scgp);
1083 	print_capacity(scgp, stderr);
1084 
1085 	parm.start = ULONG_C(0xF0000000);
1086 	parm.end =   ULONG_C(0xFF000000);
1087 	parm.name = "DDD";
1088 
1089 	rp.errors = 0;
1090 	rp.c2_errors = 0;
1091 	rp.c2_maxerrs = 0;
1092 	rp.c2_errsecs = 0;
1093 	rp.c2_badsecs = 0;
1094 	rp.isecsize = rp.secsize = 2448;
1095 	rp.ismmc = is_mmc(scgp, NULL, NULL);
1096 	domode(scgp, -1, -1);
1097 	read_generic(scgp, &parm, fread_lin, &rp, fdata_null);
1098 }
1099 
1100 LOCAL int
read_secheader(scgp,addr)1101 read_secheader(scgp, addr)
1102 	SCSI	*scgp;
1103 	long	addr;
1104 {
1105 	rparm_t	rp;
1106 	int	osecsize = 2048;
1107 	int	ret = 0;
1108 
1109 	scgp->silent++;
1110 	if (read_capacity(scgp) >= 0)
1111 		osecsize = scgp->cap->c_bsize;
1112 	scgp->silent--;
1113 	if (osecsize != 2048)
1114 		select_secsize(scgp, 2048);
1115 
1116 	read_capacity(scgp);
1117 
1118 	rp.errors = 0;
1119 	rp.c2_errors = 0;
1120 	rp.c2_maxerrs = 0;
1121 	rp.c2_errsecs = 0;
1122 	rp.c2_badsecs = 0;
1123 	rp.isecsize = rp.secsize = 2352;
1124 	rp.ismmc = is_mmc(scgp, NULL, NULL);
1125 
1126 	wait_unit_ready(scgp, 10);
1127 
1128 	fillbytes(Sbuf, 2352, '\0');
1129 	if (fread_2352(scgp, &rp, Sbuf, addr, 1) < 0) {
1130 		ret = -1;
1131 	}
1132 	if (osecsize != 2048)
1133 		select_secsize(scgp, osecsize);
1134 	return (ret);
1135 }
1136 
1137 /* ARGSUSED */
1138 LOCAL int
read_ftoc(scgp,parmp,do_sectype)1139 read_ftoc(scgp, parmp, do_sectype)
1140 	SCSI	*scgp;
1141 	parm_t	*parmp;
1142 	BOOL	do_sectype;
1143 {
1144 	FILE	*f;
1145 	int	i;
1146 	char	filename[1024];
1147 	struct	tocheader *tp;
1148 	char	*p;
1149 	char	xb[256];
1150 	int	len;
1151 	char	xxb[10000];
1152 
1153 
1154 	strcpy(filename, "toc.dat");
1155 	if (parmp != NULL &&
1156 	    strcmp(parmp->name, "/dev/null") != 0) {
1157 
1158 		len = strlen(parmp->name);
1159 		if (len > (sizeof (filename)-5)) {
1160 			len = sizeof (filename)-5;
1161 		}
1162 		js_snprintf(filename, sizeof (filename), "%.*s.toc", len, parmp->name);
1163 	}
1164 
1165 	tp = (struct tocheader *)xb;
1166 
1167 	fillbytes((caddr_t)xb, sizeof (xb), '\0');
1168 	if (read_toc(scgp, xb, 0, sizeof (struct tocheader), 0, FMT_FULLTOC) < 0) {
1169 		if (scgp->silent == 0 || scgp->verbose > 0)
1170 			errmsgno(EX_BAD, _("Cannot read TOC header\n"));
1171 		return (-1);
1172 	}
1173 	len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
1174 	error(_("TOC len: %d. First Session: %d Last Session: %d.\n"), len, tp->first, tp->last);
1175 
1176 	/*
1177 	 * XXX there is a bug in some ASPI versions that
1178 	 * XXX cause a hang with odd transfer lengths.
1179 	 * XXX We should workaround the problem where it exists
1180 	 * XXX but the problem may exist elsewhere too.
1181 	 */
1182 	if (len & 1)
1183 		len++;
1184 	if (read_toc(scgp, xxb, 0, len, 0, FMT_FULLTOC) < 0) {
1185 		if (len & 1) {
1186 			/*
1187 			 * Work around a bug in some operating systems that do not
1188 			 * handle odd byte DMA correctly for ATAPI drives.
1189 			 */
1190 			wait_unit_ready(scgp, 30);
1191 			read_toc(scgp, xb, 0, sizeof (struct tocheader), 0, FMT_FULLTOC);
1192 			wait_unit_ready(scgp, 30);
1193 			if (read_toc(scgp, xxb, 0, len+1, 0, FMT_FULLTOC) >= 0) {
1194 				goto itworked;
1195 			}
1196 		}
1197 		if (scgp->silent == 0)
1198 			errmsgno(EX_BAD, _("Cannot read full TOC\n"));
1199 		return (-1);
1200 	}
1201 
1202 itworked:
1203 	f = fileopen(filename, "wctb");
1204 
1205 	if (f == NULL)
1206 		comerr(_("Cannot open '%s'.\n"), filename);
1207 	filewrite(f, xxb, len);
1208 	if (do_sectype)
1209 		read_sectypes(scgp, f);
1210 	fflush(f);
1211 	fclose(f);
1212 
1213 	p = &xxb[4];
1214 	for (; p < &xxb[len]; p += 11) {
1215 		for (i = 0; i < 11; i++)
1216 			error("%02X ", p[i] & 0xFF);
1217 		error("\n");
1218 	}
1219 	/*
1220 	 * List all lead out start times to give information about multi
1221 	 * session disks.
1222 	 */
1223 	p = &xxb[4];
1224 	for (; p < &xxb[len]; p += 11) {
1225 		if ((p[3] & 0xFF) == 0xA2) {
1226 			error(_("Lead out %d: %ld\n"), p[0], msf_to_lba(p[8], p[9], p[10], TRUE));
1227 		}
1228 	}
1229 	return (0);
1230 }
1231 
1232 LOCAL void
read_sectypes(scgp,f)1233 read_sectypes(scgp, f)
1234 	SCSI	*scgp;
1235 	FILE	*f;
1236 {
1237 	char	sect;
1238 
1239 	sect = SECT_AUDIO;
1240 	get_sectype(scgp, 4, &sect);
1241 	if (f != NULL)
1242 		filewrite(f, &sect, 1);
1243 	if (xdebug)
1244 		scg_prbytes(_("sec 0"), (Uchar *)Sbuf, 16);
1245 
1246 	sect = SECT_AUDIO;
1247 	get_sectype(scgp, scgp->cap->c_baddr-4, &sect);
1248 	if (f != NULL)
1249 		filewrite(f, &sect, 1);
1250 	if (xdebug) {
1251 		scg_prbytes(_("sec E"), (Uchar *)Sbuf, 16);
1252 		error(_("baddr: %ld\n"), (long)scgp->cap->c_baddr);
1253 	}
1254 }
1255 
1256 LOCAL void
get_sectype(scgp,addr,st)1257 get_sectype(scgp, addr, st)
1258 	SCSI	*scgp;
1259 	long	addr;
1260 	char	*st;
1261 {
1262 	char	*synchdr = "\0\377\377\377\377\377\377\377\377\377\377\0";
1263 	int	sectype = SECT_AUDIO;
1264 	int	i;
1265 	long	raddr = addr;
1266 #define	_MAX_TRY_	20
1267 
1268 	scgp->silent++;
1269 	for (i = 0; i < _MAX_TRY_ && read_secheader(scgp, raddr) < 0; i++) {
1270 		if (addr == 0)
1271 			raddr++;
1272 		else
1273 			raddr--;
1274 	}
1275 	scgp->silent--;
1276 	if (i >= _MAX_TRY_) {
1277 		error(_("Sectype (%ld) is CANNOT\n"), addr);
1278 		return;
1279 	} else if (i > 0) {
1280 		error(_("Sectype (%ld) needed %d retries\n"), addr, i);
1281 	}
1282 #undef	_MAX_TRY_
1283 
1284 	if (cmpbytes(Sbuf, synchdr, 12) < 12) {
1285 		if (xdebug)
1286 			error(_("Sectype (%ld) is AUDIO\n"), addr);
1287 		if (st)
1288 			*st = SECT_AUDIO;
1289 		return;
1290 	}
1291 	if (xdebug)
1292 		error(_("Sectype (%ld) is DATA\n"), addr);
1293 	if (Sbuf[15] == 0) {
1294 		if (xdebug)
1295 			error(_("Sectype (%ld) is MODE 0\n"), addr);
1296 		sectype = SECT_MODE_0;
1297 
1298 	} else if (Sbuf[15] == 1) {
1299 		if (xdebug)
1300 			error(_("Sectype (%ld) is MODE 1\n"), addr);
1301 		sectype = SECT_ROM;
1302 
1303 	} else if (Sbuf[15] == 2) {
1304 		if (xdebug)
1305 			error(_("Sectype (%ld) is MODE 2\n"), addr);
1306 
1307 		if ((Sbuf[16+2]  & 0x20) == 0 &&
1308 		    (Sbuf[16+4+2]  & 0x20) == 0) {
1309 			if (xdebug)
1310 				error(_("Sectype (%ld) is MODE 2 form 1\n"), addr);
1311 			sectype = SECT_MODE_2_F1;
1312 
1313 		} else if ((Sbuf[16+2]  & 0x20) != 0 &&
1314 		    (Sbuf[16+4+2]  & 0x20) != 0) {
1315 			if (xdebug)
1316 				error(_("Sectype (%ld) is MODE 2 form 2\n"), addr);
1317 			sectype = SECT_MODE_2_F2;
1318 		} else {
1319 			if (xdebug)
1320 				error(_("Sectype (%ld) is MODE 2 formless\n"), addr);
1321 			sectype = SECT_MODE_2;
1322 		}
1323 	} else {
1324 		error(_("Sectype (%ld) is UNKNOWN\n"), addr);
1325 	}
1326 	if (st)
1327 		*st = sectype;
1328 	if (xdebug)
1329 		error(_("Sectype (%ld) is 0x%02X\n"), addr, sectype);
1330 }
1331 
1332 #endif	/* CLONE_WRITE */
1333 
1334 char	zeroblk[512];
1335 
1336 LOCAL void
readc2_disk(scgp,parmp)1337 readc2_disk(scgp, parmp)
1338 	SCSI	*scgp;
1339 	parm_t	*parmp;
1340 {
1341 	rparm_t	rp;
1342 	int	osecsize = 2048;
1343 	int	oerr = 0;
1344 	int	oretr = 10;
1345 
1346 	scgp->silent++;
1347 	if (read_capacity(scgp) >= 0)
1348 		osecsize = scgp->cap->c_bsize;
1349 	scgp->silent--;
1350 	if (osecsize != 2048)
1351 		select_secsize(scgp, 2048);
1352 
1353 	read_capacity(scgp);
1354 	print_capacity(scgp, stderr);
1355 
1356 	rp.errors = 0;
1357 	rp.c2_errors = 0;
1358 	rp.c2_maxerrs = 0;
1359 	rp.c2_errsecs = 0;
1360 	rp.c2_badsecs = 0;
1361 	rp.isecsize = rp.secsize = 2352 + 294;	/* CD-DA + C2 bit pointers */
1362 	rp.ismmc = is_mmc(scgp, NULL, NULL);
1363 
1364 	oldmode(scgp, &oerr, &oretr);
1365 	exargs.oerr[0] = oerr;
1366 	exargs.oerr[1] = oretr;
1367 	exargs.oerr[2] = 0xFF;
1368 	domode(scgp, 0x21, 10);
1369 
1370 
1371 	read_generic(scgp, parmp, fread_c2, &rp, fdata_c2);
1372 	if (osecsize != 2048)
1373 		select_secsize(scgp, osecsize);
1374 	domode(scgp, oerr, oretr);
1375 
1376 	printf(_("Total of %d hard read errors.\n"), rp.errors);
1377 	printf(_("C2 errors total: %d bytes in %d sectors on disk\n"), rp.c2_errors, rp.c2_errsecs);
1378 	printf(_("C2 errors rate: %f%% per byte, %f%% per sector\n"),
1379 			(100.0*rp.c2_errors)/scgp->cap->c_baddr/2352,
1380 			(100.0*rp.c2_errsecs)/scgp->cap->c_baddr);
1381 	printf(_("C2 errors on worst sector: %d, sectors with 100+ C2 errors: %d\n"), rp.c2_maxerrs, rp.c2_badsecs);
1382 }
1383 
1384 
1385 LOCAL void
readcx_disk(scgp,parmp)1386 readcx_disk(scgp, parmp)
1387 	SCSI	*scgp;
1388 	parm_t	*parmp;
1389 {
1390 	long			addr = 0L;
1391 	long			end = 0L;
1392 	int			secs;	/* # of seconds */
1393 	cxerror_t		errors;
1394 	cxerror_t		stats;
1395 	cxerror_t		max_errors;
1396 	cx_scan_procedure_t	*sp;
1397 	BOOL			askrange = FALSE;
1398 	BOOL			isrange = FALSE;
1399 	FILE			*f = stdout;
1400 
1401 	if (is_suid) {
1402 		if (scgp->inq->type != INQ_ROMD)
1403 			comerrno(EX_BAD, _("Not root. Will only read from CD in suid/priv mode\n"));
1404 	}
1405 
1406 	scgp->silent++;
1407 	if (read_capacity(scgp) >= 0)
1408 		end = scgp->cap->c_baddr + 1;
1409 	scgp->silent--;
1410 	print_capacity(scgp, stderr);
1411 
1412 	if (parmp == NULL || parmp->askrange)
1413 		askrange = TRUE;
1414 	if (parmp != NULL && !askrange && (parmp->start <= parmp->end))
1415 		isrange = TRUE;
1416 
1417 	if ((end <= 0 && isrange) || (askrange && scg_yes(_("Ignore disk size? "))))
1418 		end = 10000000;	/* Hack to read empty (e.g. blank=fast) disks */
1419 
1420 	if (parmp) {
1421 		addr = parmp->start;
1422 		if (parmp->end != -1 && parmp->end < end)
1423 			end = parmp->end;
1424 	}
1425 
1426 	for (sp = cx_scan_procedures; sp->start_func; sp++) {
1427 		if ((*sp->start_func)(scgp) >= 0)
1428 			break;
1429 	}
1430 	if (sp->start_func == NULL)
1431 		comerrno(EX_BAD, _("Unsupported drive for -cxscan\n"));
1432 
1433 	secs = (end - addr) / 75;	/* Compute # of seconds */
1434 
1435 	fillbytes(&stats, sizeof (stats), '\0');
1436 	fillbytes(&max_errors, sizeof (max_errors), '\0');
1437 
1438 	while (addr < end) {
1439 		addr = (*sp->one_interval_func)(scgp, &errors, addr, Sbuf);
1440 		stats.c1_errors += errors.c1_errors;
1441 		stats.c2_errors += errors.c2_errors;
1442 		stats.cu_errors += errors.cu_errors;
1443 		stats.pi_errors += errors.pi_errors;
1444 		max_errors.c1_errors = max(max_errors.c1_errors, errors.c1_errors);
1445 		max_errors.c2_errors = max(max_errors.c2_errors, errors.c2_errors);
1446 		max_errors.cu_errors = max(max_errors.cu_errors, errors.cu_errors);
1447 		max_errors.pi_errors = max(max_errors.pi_errors, errors.pi_errors);
1448 		if (lverbose > 1 ||
1449 		    (lverbose > 0 &&
1450 		    (errors.c1_errors || errors.c2_errors || errors.cu_errors))) {
1451 			if (plot) {
1452 				printf("%8ld %4d %4d %4d\n",
1453 				addr,
1454 				errors.c1_errors, errors.c2_errors,
1455 				errors.cu_errors);
1456 				flush();
1457 			} else {
1458 				printf(" %3ldm %02lds: C1: %4d,  C2: %4d,  CU: %4d\n",
1459 				addr/75/60, addr/75%60,
1460 				errors.c1_errors, errors.c2_errors,
1461 				errors.cu_errors);
1462 			}
1463 		}
1464 		if (didintr) {
1465 			(*sp->end_func)(scgp);
1466 			comexit(exsig);
1467 		}
1468 	}
1469 
1470 	if (plot)
1471 		f = stderr;
1472 	fprintf(f, _("\n\ntotal result:\n\n"));
1473 	fprintf(f, _("total:   C1: %5d,   C2: %5d,   CU: %5d\n"),
1474 			stats.c1_errors, stats.c2_errors, stats.cu_errors);
1475 	fprintf(f, _("max  :   C1: %5d,   C2: %5d,   CU: %5d\n"),
1476 			max_errors.c1_errors, max_errors.c2_errors,
1477 			max_errors.cu_errors);
1478 	fprintf(f, _("avg/s:   C1: %5.1f,   C2: %5.1f,   CU: %5.1f\n\n"),
1479 			(float)stats.c1_errors/secs,
1480 			(float)stats.c2_errors/secs,
1481 			(float)stats.cu_errors/secs);
1482 
1483 	(*sp->end_func)(scgp);
1484 }
1485 
1486 
1487 LOCAL void
readpi_disk(scgp,parmp)1488 readpi_disk(scgp, parmp)
1489 	SCSI	*scgp;
1490 	parm_t	*parmp;
1491 {
1492 	long			addr = 0L;
1493 	long			end = 0L;
1494 	int			secs;	/* # of seconds */
1495 	cxerror_t		errors;
1496 	cxerror_t		stats;
1497 	cxerror_t		max_errors;
1498 	BOOL			askrange = FALSE;
1499 	BOOL			isrange = FALSE;
1500 	FILE			*f = stdout;
1501 
1502 	if (is_suid) {
1503 		if (scgp->inq->type != INQ_ROMD)
1504 			comerrno(EX_BAD, _("Not root. Will only read from CD in suid/priv mode\n"));
1505 	}
1506 
1507 	scgp->silent++;
1508 	if (read_capacity(scgp) >= 0)
1509 		end = scgp->cap->c_baddr + 1;
1510 	scgp->silent--;
1511 	print_capacity(scgp, stderr);
1512 
1513 	if (parmp == NULL || parmp->askrange)
1514 		askrange = TRUE;
1515 	if (parmp != NULL && !askrange && (parmp->start <= parmp->end))
1516 		isrange = TRUE;
1517 
1518 	if ((end <= 0 && isrange) || (askrange && scg_yes(_("Ignore disk size? "))))
1519 		end = 10000000;	/* Hack to read empty (e.g. blank=fast) disks */
1520 
1521 	if (parmp) {
1522 		addr = parmp->start;
1523 		if (parmp->end != -1 && parmp->end < end)
1524 			end = parmp->end;
1525 	}
1526 
1527 	if (pifscan) {
1528 		if (plextor_init_pif_scan(scgp) < 0)
1529 			comerrno(EX_BAD, _("Unsupported drive for -pifscan\n"));
1530 	} else if (plextor_init_pi8_scan(scgp) < 0)
1531 		comerrno(EX_BAD, _("Unsupported drive for -pi8scan\n"));
1532 
1533 	secs = (end - addr) / (8*16);	/* Compute # of blocks */
1534 	if (pifscan)
1535 		secs = (end - addr) / (16);	/* Compute # of blocks */
1536 
1537 	fillbytes(&stats, sizeof (stats), '\0');
1538 	fillbytes(&max_errors, sizeof (max_errors), '\0');
1539 
1540 	while (addr < end) {
1541 		addr = plextor_scan_one_dvd_interval(scgp, &errors, addr, Sbuf);
1542 		stats.c1_errors += errors.c1_errors;
1543 		stats.c2_errors += errors.c2_errors;
1544 		stats.cu_errors += errors.cu_errors;
1545 		stats.pi_errors += errors.pi_errors;
1546 		max_errors.c1_errors = max(max_errors.c1_errors, errors.c1_errors);
1547 		max_errors.c2_errors = max(max_errors.c2_errors, errors.c2_errors);
1548 		max_errors.cu_errors = max(max_errors.cu_errors, errors.cu_errors);
1549 		max_errors.pi_errors = max(max_errors.pi_errors, errors.pi_errors);
1550 		if (lverbose > 1 ||
1551 		    (lverbose > 0 && errors.pi_errors)) {
1552 			printf(" %8ld %6d\n",
1553 				addr,
1554 				errors.pi_errors);
1555 			if (plot)
1556 				flush();
1557 		}
1558 		if (didintr) {
1559 			plextor_end_scan(scgp);
1560 			comexit(exsig);
1561 		}
1562 	}
1563 
1564 	if (plot)
1565 		f = stderr;
1566 	fprintf(f, _("\n\ntotal result:\n\n"));
1567 	fprintf(f, _("total:   PI: %8d\n"),
1568 			stats.pi_errors);
1569 	fprintf(f, _("max  :   PI: %8d\n"),
1570 			max_errors.pi_errors);
1571 	fprintf(f, _("avg sum: PI: %8.1f\n\n"),
1572 			(float)stats.pi_errors/secs);
1573 
1574 	plextor_end_scan(scgp);
1575 }
1576 
1577 
1578 /* ARGSUSED */
1579 LOCAL int
fread_data(scgp,rp,bp,addr,cnt)1580 fread_data(scgp, rp, bp, addr, cnt)
1581 	SCSI	*scgp;
1582 	rparm_t	*rp;
1583 	caddr_t	bp;
1584 	long	addr;
1585 	int	cnt;
1586 {
1587 	return (read_g1(scgp, bp, addr, cnt));
1588 }
1589 
1590 #ifdef	CLONE_WRITE
1591 LOCAL int
fread_2448(scgp,rp,bp,addr,cnt)1592 fread_2448(scgp, rp, bp, addr, cnt)
1593 	SCSI	*scgp;
1594 	rparm_t	*rp;
1595 	caddr_t	bp;
1596 	long	addr;
1597 	int	cnt;
1598 {
1599 	if (rp->ismmc) {
1600 		return (read_cd(scgp, bp, addr, cnt, rp->secsize,
1601 			/* Sync + all headers + user data + EDC/ECC */
1602 			(1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1603 			/* plus all subchannels RAW */
1604 			1));
1605 	} else {
1606 		return (read_da(scgp, bp, addr, cnt, rp->secsize,
1607 			/* Sync + all headers + user data + EDC/ECC + all subch */
1608 			0x02));
1609 	}
1610 }
1611 
1612 LOCAL int
fread_2448_16(scgp,rp,bp,addr,cnt)1613 fread_2448_16(scgp, rp, bp, addr, cnt)
1614 	SCSI	*scgp;
1615 	rparm_t	*rp;
1616 	caddr_t	bp;
1617 	long	addr;
1618 	int	cnt;
1619 {
1620 
1621 	if (rp->ismmc) {
1622 		track_t trackdesc;
1623 		int	ret;
1624 		int	i;
1625 		char	*p;
1626 
1627 		trackdesc.isecsize = 2368;
1628 		trackdesc.secsize = 2448;
1629 		ret = read_cd(scgp, bp, addr, cnt, 2368,
1630 			/* Sync + all headers + user data + EDC/ECC */
1631 			(1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1632 			/* subchannels P/Q */
1633 			2);
1634 		if (ret < 0)
1635 			return (ret);
1636 
1637 		scatter_secs(&trackdesc, bp, cnt);
1638 		for (i = 0, p = bp+2352; i < cnt; i++) {
1639 #ifdef	more_than_q_sub
1640 			if ((p[15] & 0x80) != 0)
1641 				printf("P");
1642 #endif
1643 			/*
1644 			 * As the drives don't return P-sub, we check
1645 			 * whether the index equals 0.
1646 			 */
1647 			qpto96((Uchar *)p, (Uchar *)p, p[2] == 0);
1648 			p += 2448;
1649 		}
1650 		return (ret);
1651 	} else {
1652 		comerrno(EX_BAD, _("Cannot fread_2448_16 on non MMC drives\n"));
1653 
1654 		return (read_da(scgp, bp, addr, cnt, rp->secsize,
1655 			/* Sync + all headers + user data + EDC/ECC + all subch */
1656 			0x02));
1657 	}
1658 }
1659 
1660 LOCAL int
fread_2352(scgp,rp,bp,addr,cnt)1661 fread_2352(scgp, rp, bp, addr, cnt)
1662 	SCSI	*scgp;
1663 	rparm_t	*rp;
1664 	caddr_t	bp;
1665 	long	addr;
1666 	int	cnt;
1667 {
1668 	if (rp->ismmc) {
1669 		return (read_cd(scgp, bp, addr, cnt, rp->secsize,
1670 			/* Sync + all headers + user data + EDC/ECC */
1671 			(1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1672 			/* NO subchannels */
1673 			0));
1674 	} else {
1675 		comerrno(EX_BAD, _("Cannot fread_2352 on non MMC drives\n"));
1676 
1677 		return (read_da(scgp, bp, addr, cnt, rp->secsize,
1678 			/* Sync + all headers + user data + EDC/ECC + all subch */
1679 			0x02));
1680 	}
1681 }
1682 
1683 /*
1684  * -ledc_ecc_dec read variant:	read CD-DA sectors (2352 bytes) and output
1685  *				corrected CD-ROM sectors (2048 bytes).
1686  */
1687 int edc_OK = 0;
1688 LOCAL int
fread_2048(scgp,rp,bp,addr,cnt)1689 fread_2048(scgp, rp, bp, addr, cnt)
1690 	SCSI	*scgp;
1691 	rparm_t	*rp;
1692 	caddr_t	bp;
1693 	long	addr;
1694 	int	cnt;
1695 {
1696 	int	ret;
1697 	char	*from;
1698 	char	*to;
1699 	char	*p;
1700 	int	i = 0;
1701 	int	secsize = rp->secsize;
1702 	BOOL	OK = TRUE;
1703 
1704 	rp->secsize = rp->isecsize;
1705 	fillbytes(bp, rp->secsize * cnt, '\0');
1706 	ret = fread_2352(scgp, rp, bp, addr, cnt);
1707 	rp->secsize = secsize;
1708 
1709 	from = bp;
1710 	from += 16;
1711 	to = bp;
1712 	p = bp;
1713 	while (i < cnt) {
1714 		int	crc;
1715 
1716 		crc = crc_check((unsigned char *)p, MODE_1);
1717 		ret = do_decode_L2((unsigned char *)p, MODE_1, FALSE, 0);
1718 
1719 		if (ret < 0)
1720 			OK = FALSE;
1721 		if (crc == 0 && ret == 0) {
1722 			edc_OK++;
1723 			error("Corrected: total %d Block %ld\n", edc_OK, addr+i);
1724 		}
1725 		move2048(from, to);
1726 		from += 2352;
1727 		to += 2048;
1728 		p += 2352;
1729 		i++;
1730 	}
1731 	if (OK)
1732 		return (0);
1733 	else
1734 		return (-1);
1735 }
1736 
1737 LOCAL int
fread_lin(scgp,rp,bp,addr,cnt)1738 fread_lin(scgp, rp, bp, addr, cnt)
1739 	SCSI	*scgp;
1740 	rparm_t	*rp;
1741 	caddr_t	bp;
1742 	long	addr;
1743 	int	cnt;
1744 {
1745 	if (addr != ULONG_C(0xF0000000))
1746 		addr = ULONG_C(0xFFFFFFFF);
1747 
1748 	return (read_cd(scgp, bp, addr, cnt, rp->secsize,
1749 		/* Sync + all headers + user data + EDC/ECC */
1750 		(1 << 7 | 3 << 5 | 1 << 4 | 1 << 3),
1751 		/* plus all subchannels RAW */
1752 		1));
1753 }
1754 #endif	/* CLONE_WRITE */
1755 
1756 LOCAL int
bits(c)1757 bits(c)
1758 	int	c;
1759 {
1760 	int	n = 0;
1761 
1762 	if (c & 0x01)
1763 		n++;
1764 	if (c & 0x02)
1765 		n++;
1766 	if (c & 0x04)
1767 		n++;
1768 	if (c & 0x08)
1769 		n++;
1770 	if (c & 0x10)
1771 		n++;
1772 	if (c & 0x20)
1773 		n++;
1774 	if (c & 0x40)
1775 		n++;
1776 	if (c & 0x80)
1777 		n++;
1778 	return (n);
1779 }
1780 
1781 LOCAL int
bitidx(c)1782 bitidx(c)
1783 	int	c;
1784 {
1785 	if (c & 0x80)
1786 		return (0);
1787 	if (c & 0x40)
1788 		return (1);
1789 	if (c & 0x20)
1790 		return (2);
1791 	if (c & 0x10)
1792 		return (3);
1793 	if (c & 0x08)
1794 		return (4);
1795 	if (c & 0x04)
1796 		return (5);
1797 	if (c & 0x02)
1798 		return (6);
1799 	if (c & 0x01)
1800 		return (7);
1801 	return (-1);
1802 }
1803 
1804 LOCAL int
fread_c2(scgp,rp,bp,addr,cnt)1805 fread_c2(scgp, rp, bp, addr, cnt)
1806 	SCSI	*scgp;
1807 	rparm_t	*rp;
1808 	caddr_t	bp;
1809 	long	addr;
1810 	int	cnt;
1811 {
1812 	if (rp->ismmc) {
1813 		return (read_cd(scgp, bp, addr, cnt, rp->secsize,
1814 			/* Sync + all headers + user data + EDC/ECC + C2 */
1815 /*			(1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 2 << 1),*/
1816 			(1 << 7 | 3 << 5 | 1 << 4 | 1 << 3 | 1 << 1),
1817 			/* without subchannels */
1818 			0));
1819 	} else {
1820 		return (read_da(scgp, bp, addr, cnt, rp->secsize,
1821 			/* Sync + all headers + user data + EDC/ECC + C2 */
1822 			0x04));
1823 	}
1824 }
1825 
1826 /* ARGSUSED */
1827 LOCAL int
fdata_null(rp,bp,addr,cnt)1828 fdata_null(rp, bp, addr, cnt)
1829 	rparm_t	*rp;
1830 	caddr_t	bp;
1831 	long	addr;
1832 	int	cnt;
1833 {
1834 	return (0);
1835 }
1836 
1837 LOCAL int
fdata_c2(rp,bp,addr,cnt)1838 fdata_c2(rp, bp, addr, cnt)
1839 	rparm_t	*rp;
1840 	caddr_t	bp;
1841 	long	addr;
1842 	int	cnt;
1843 {
1844 	int	i;
1845 	int	j;
1846 	int	k;
1847 	char	*p;
1848 
1849 	p = &bp[2352];
1850 
1851 	for (i = 0; i < cnt; i++, p += (2352+294)) {
1852 /*		scg_prbytes("XXX ", p, 294);*/
1853 		if ((j = cmpbytes(p, zeroblk, 294)) < 294) {
1854 			printf(_("C2 in sector: %3ld first at byte: %4d (0x%02X)"), addr+i,
1855 				j*8 + bitidx(p[j]), p[j]&0xFF);
1856 			for (j = 0, k = 0; j < 294; j++)
1857 				k += bits(p[j]);
1858 			printf(_(" total: %4d errors\n"), k);
1859 /*			scg_prbytes("XXX ", p, 294);*/
1860 			rp->c2_errors += k;
1861 			if (k > rp->c2_maxerrs)
1862 				rp->c2_maxerrs = k;
1863 			rp->c2_errsecs++;
1864 			if (k >= 100)
1865 				rp->c2_badsecs += 1;
1866 		}
1867 	}
1868 	return (0);
1869 }
1870 
1871 #ifdef	used
1872 LOCAL int
read_scsi_g1(scgp,bp,addr,cnt)1873 read_scsi_g1(scgp, bp, addr, cnt)
1874 	SCSI	*scgp;
1875 	caddr_t	bp;
1876 	long	addr;
1877 	int	cnt;
1878 {
1879 	register struct	scg_cmd	*scmd = scgp->scmd;
1880 
1881 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1882 	scmd->addr = bp;
1883 /*	scmd->size = cnt*512;*/
1884 	scmd->size = cnt*scgp->cap->c_bsize;
1885 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1886 	scmd->cdb_len = SC_G1_CDBLEN;
1887 	scmd->sense_len = CCS_SENSE_LEN;
1888 	scmd->cdb.g1_cdb.cmd = 0x28;
1889 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
1890 	g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
1891 	g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1892 
1893 	scgp->cmdname = "read extended";
1894 
1895 	return (scg_cmd(scgp));
1896 }
1897 #endif
1898 
1899 #define	G0_MAXADDR	0x1FFFFFL
1900 
1901 EXPORT int
write_scsi(scgp,bp,addr,cnt)1902 write_scsi(scgp, bp, addr, cnt)
1903 	SCSI	*scgp;
1904 	caddr_t	bp;
1905 	long	addr;
1906 	int	cnt;
1907 {
1908 	if (addr <= G0_MAXADDR)
1909 		return (write_g0(scgp, bp, addr, cnt));
1910 	else
1911 		return (write_g1(scgp, bp, addr, cnt));
1912 }
1913 
1914 EXPORT int
write_g0(scgp,bp,addr,cnt)1915 write_g0(scgp, bp, addr, cnt)
1916 	SCSI	*scgp;
1917 	caddr_t	bp;
1918 	long	addr;
1919 	int	cnt;
1920 {
1921 	register struct	scg_cmd	*scmd = scgp->scmd;
1922 
1923 	if (scgp->cap->c_bsize <= 0)
1924 		raisecond("capacity_not_set", 0L);
1925 
1926 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1927 	scmd->addr = bp;
1928 	scmd->size = cnt*scgp->cap->c_bsize;
1929 	scmd->flags = SCG_DISRE_ENA;
1930 	scmd->cdb_len = SC_G0_CDBLEN;
1931 	scmd->sense_len = CCS_SENSE_LEN;
1932 	scmd->cdb.g0_cdb.cmd = SC_WRITE;
1933 	scmd->cdb.g0_cdb.lun = scg_lun(scgp);
1934 	g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
1935 	scmd->cdb.g0_cdb.count = (Uchar)cnt;
1936 
1937 	scgp->cmdname = "write_g0";
1938 
1939 	return (scg_cmd(scgp));
1940 }
1941 
1942 EXPORT int
write_g1(scgp,bp,addr,cnt)1943 write_g1(scgp, bp, addr, cnt)
1944 	SCSI	*scgp;
1945 	caddr_t	bp;
1946 	long	addr;
1947 	int	cnt;
1948 {
1949 	register struct	scg_cmd	*scmd = scgp->scmd;
1950 
1951 	if (scgp->cap->c_bsize <= 0)
1952 		raisecond("capacity_not_set", 0L);
1953 
1954 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1955 	scmd->addr = bp;
1956 	scmd->size = cnt*scgp->cap->c_bsize;
1957 	scmd->flags = SCG_DISRE_ENA;
1958 	scmd->cdb_len = SC_G1_CDBLEN;
1959 	scmd->sense_len = CCS_SENSE_LEN;
1960 	scmd->cdb.g1_cdb.cmd = SC_EWRITE;
1961 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
1962 	g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
1963 	g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1964 
1965 	scgp->cmdname = "write_g1";
1966 
1967 	return (scg_cmd(scgp));
1968 }
1969 
1970 #ifdef	used
1971 LOCAL void
Xrequest_sense(scgp)1972 Xrequest_sense(scgp)
1973 	SCSI	*scgp;
1974 {
1975 	char	sense_buf[32];
1976 	struct	scg_cmd ocmd;
1977 	int	sense_count;
1978 	char	*cmdsave;
1979 	register struct	scg_cmd	*scmd = scgp->scmd;
1980 
1981 	cmdsave = scgp->cmdname;
1982 
1983 	movebytes(scmd, &ocmd, sizeof (*scmd));
1984 
1985 	fillbytes((caddr_t)sense_buf, sizeof (sense_buf), '\0');
1986 
1987 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1988 	scmd->addr = (caddr_t)sense_buf;
1989 	scmd->size = sizeof (sense_buf);
1990 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1991 	scmd->cdb_len = SC_G0_CDBLEN;
1992 	scmd->sense_len = CCS_SENSE_LEN;
1993 	scmd->cdb.g1_cdb.cmd = 0x3;
1994 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
1995 	scmd->cdb.g0_cdb.count = sizeof (sense_buf);
1996 
1997 	scgp->cmdname = "request sense";
1998 
1999 	scg_cmd(scgp);
2000 
2001 	sense_count = sizeof (sense_buf) - scg_getresid(scgp);
2002 	movebytes(&ocmd, scmd, sizeof (*scmd));
2003 	scmd->sense_count = sense_count;
2004 	movebytes(sense_buf, (Uchar *)&scmd->sense, scmd->sense_count);
2005 
2006 	scgp->cmdname = cmdsave;
2007 	scg_printerr(scgp);
2008 	scg_printresult(scgp);	/* XXX restore key/code in future */
2009 }
2010 #endif
2011 
2012 LOCAL int
read_retry(scgp,bp,addr,cnt,rfunc,rp)2013 read_retry(scgp, bp, addr, cnt, rfunc, rp)
2014 	SCSI	*scgp;
2015 	caddr_t	bp;
2016 	long	addr;
2017 	long	cnt;
2018 	int	(*rfunc)__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
2019 	rparm_t	*rp;
2020 {
2021 /*	int	secsize = scgp->cap->c_bsize;*/
2022 	int	secsize = rp->secsize;
2023 	int	try = 0;
2024 	int	err;
2025 	char	dummybuf[8192];
2026 
2027 	if (secsize > sizeof (dummybuf)) {
2028 		errmsgno(EX_BAD, _("Cannot retry, sector size %d too big.\n"), secsize);
2029 		return (-1);
2030 	}
2031 
2032 	errmsgno(EX_BAD, _("Retrying from sector %ld.\n"), addr);
2033 	while (cnt > 0) {
2034 		error(".");
2035 
2036 		do {
2037 			if (didintr)
2038 				comexit(exsig);		/* XXX besseres Konzept?!*/
2039 			wait_unit_ready(scgp, 120);
2040 			if (try >= 10) {		/* First 10 retries without seek */
2041 				if ((try % 8) == 0) {
2042 					error("+");	/* Read last sector */
2043 					scgp->silent++;
2044 					(*rfunc)(scgp, rp, dummybuf, scgp->cap->c_baddr, 1);
2045 					scgp->silent--;
2046 				} else if ((try % 4) == 0) {
2047 					error("-");	/* Read first sector */
2048 					scgp->silent++;
2049 					(*rfunc)(scgp, rp, dummybuf, 0, 1);
2050 					scgp->silent--;
2051 				} else {
2052 					error("~");	/* Read random sector */
2053 					scgp->silent++;
2054 					(*rfunc)(scgp, rp, dummybuf, choice(scgp->cap->c_baddr), 1);
2055 					scgp->silent--;
2056 				}
2057 				if (didintr)
2058 					comexit(exsig);		/* XXX besseres Konzept?!*/
2059 				wait_unit_ready(scgp, 120);
2060 			}
2061 			if (didintr)
2062 				comexit(exsig);		/* XXX besseres Konzept?!*/
2063 
2064 			fillbytes(bp, secsize, 0);
2065 
2066 			scgp->silent++;
2067 			err = (*rfunc)(scgp, rp, bp, addr, 1);
2068 			scgp->silent--;
2069 
2070 			if (err < 0) {
2071 				err = scgp->scmd->ux_errno;
2072 /*				error("\n");*/
2073 /*				errmsgno(err, "Cannot read source disk\n");*/
2074 			} else {
2075 				if (scg_getresid(scgp)) {
2076 					error(_("\nresid: %d\n"), scg_getresid(scgp));
2077 					/*
2078 					 * If we use -ledc_ecc_dec for
2079 					 * correction, let the correction
2080 					 * happen on an upper layer.
2081 					 */
2082 					if (!edc_corr)
2083 						return (-1);
2084 				}
2085 				break;
2086 			}
2087 		} while (++try < retries);
2088 
2089 		if (try >= retries) {
2090 			error("\n");
2091 			errmsgno(err, _("Error on sector %ld not corrected. Total of %d errors.\n"),
2092 					addr, ++rp->errors);
2093 
2094 			if (scgp->silent <= 1 && lverbose > 0)
2095 				scg_printerr(scgp);
2096 
2097 			add_bad(addr);
2098 
2099 			if (!noerror)
2100 				return (-1);
2101 			errmsgno(EX_BAD, _("-noerror set, continuing ...\n"));
2102 		} else {
2103 			if (try >= maxtry)
2104 				maxtry = try;
2105 
2106 			if (try > 1) {
2107 				error("\n");
2108 				errmsgno(EX_BAD,
2109 				_("Error on sector %ld corrected after %d tries. Total of %d errors.\n"),
2110 					addr, try, rp->errors);
2111 			}
2112 		}
2113 		try = 0;
2114 		cnt -= 1;
2115 		addr += 1;
2116 		bp += secsize;
2117 	}
2118 	return (0);
2119 }
2120 
2121 LOCAL void
read_generic(scgp,parmp,rfunc,rp,dfunc)2122 read_generic(scgp, parmp, rfunc, rp, dfunc)
2123 	SCSI	*scgp;
2124 	parm_t	*parmp;
2125 	int	(*rfunc)__PR((SCSI *scgp, rparm_t *rp, caddr_t bp, long addr, int cnt));
2126 	rparm_t	*rp;
2127 	int	(*dfunc)__PR((rparm_t *rp, caddr_t bp, long addr, int cnt));
2128 {
2129 	char	filename[512];
2130 	char	*defname = NULL;
2131 	FILE	*f;
2132 	long	addr = 0L;
2133 	long	old_addr = 0L;
2134 	long	num;
2135 	long	end = 0L;
2136 	long	start = 0L;
2137 	long	cnt = 0L;
2138 	long	next_point = 0L;
2139 	long	secs_per_point = 0L;
2140 	double  speed;
2141 	int	msec;
2142 	int	old_msec = 0;
2143 	int	err = 0;
2144 	BOOL	askrange = FALSE;
2145 	BOOL	isrange = FALSE;
2146 	int	secsize = rp->secsize;
2147 	int	i = 0;
2148 
2149 	if (is_suid) {
2150 		if (scgp->inq->type != INQ_ROMD)
2151 			comerrno(EX_BAD, _("Not root. Will only read from CD in suid/priv mode\n"));
2152 	}
2153 
2154 	if (parmp == NULL || parmp->askrange)
2155 		askrange = TRUE;
2156 	if (parmp != NULL && !askrange && (parmp->start <= parmp->end))
2157 		isrange = TRUE;
2158 
2159 	filename[0] = '\0';
2160 
2161 	scgp->silent++;
2162 	if (read_capacity(scgp) >= 0)
2163 		end = scgp->cap->c_baddr + 1;
2164 	scgp->silent--;
2165 
2166 	if ((end <= 0 && isrange) || (askrange && scg_yes(_("Ignore disk size? "))))
2167 		end = 10000000;	/* Hack to read empty (e.g. blank=fast) disks */
2168 
2169 	if (parmp) {
2170 		if (parmp->name)
2171 			defname = parmp->name;
2172 		if (defname != NULL) {
2173 			error(_("Copy from SCSI (%d,%d,%d) disk to file '%s'\n"),
2174 					scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp),
2175 					defname);
2176 		}
2177 
2178 		addr = start = parmp->start;
2179 		if (parmp->end != -1 && parmp->end < end)
2180 			end = parmp->end;
2181 		cnt = Sbufsize / secsize;
2182 		/*
2183 		 * XXX clean up this hack in future.
2184 		 */
2185 		if (edc_corr)
2186 			cnt = Sbufsize / rp->isecsize;
2187 		if (cnt > spt && spt > 0)
2188 			cnt = spt;
2189 	}
2190 
2191 	if (defname == NULL) {
2192 		defname = "disk.out";
2193 		error(_("Copy from SCSI (%d,%d,%d) disk to file\n"),
2194 					scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp));
2195 		error(_("Enter filename [%s]: "), defname); flush();
2196 		(void) getline(filename, sizeof (filename));
2197 	}
2198 
2199 	if (askrange) {
2200 		addr = start;
2201 		getlong(_("Enter starting sector for copy:"), &addr, start, end-1);
2202 /*		getlong(_("Enter starting sector for copy:"), &addr, -300, end-1);*/
2203 		start = addr;
2204 	}
2205 
2206 	if (askrange) {
2207 		num = end - addr;
2208 		getlong(_("Enter number of sectors to copy:"), &num, 1L, num);
2209 		end = addr + num;
2210 	}
2211 
2212 	if (askrange) {
2213 /* XXX askcnt */
2214 		cnt = Sbufsize / secsize;
2215 		/*
2216 		 * XXX clean up this hack in future.
2217 		 */
2218 		if (edc_corr)
2219 			cnt = Sbufsize / rp->isecsize;
2220 		if (cnt > spt && spt > 0)
2221 			cnt = spt;
2222 		getlong(_("Enter number of sectors per copy:"), &cnt, 1L, cnt);
2223 	}
2224 
2225 	if (filename[0] == '\0')
2226 		strncpy(filename, defname, sizeof (filename));
2227 	filename[sizeof (filename)-1] = '\0';
2228 	if (streql(filename, "-")) {
2229 		f = stdout;
2230 		setmode(STDOUT_FILENO, O_BINARY);
2231 	} else if ((f = fileopen(filename, notrunc?"wcub":"wctub")) == NULL)
2232 		comerr(_("Cannot open '%s'.\n"), filename);
2233 	file_raise(f, FALSE);
2234 
2235 	error(_("end:  %8ld\n"), end);
2236 	if (gettimeofday(&starttime, (struct timezone *)0) < 0)
2237 		comerr(_("Cannot get start time\n"));
2238 
2239 	if (meshpoints > 0) {
2240 		if ((end-start) < meshpoints)
2241 			secs_per_point = 1;
2242 		else
2243 			secs_per_point = (end-start) / meshpoints;
2244 		next_point = start + secs_per_point;
2245 		old_addr = start;
2246 	}
2247 
2248 	for (; addr < end; addr += cnt) {
2249 		if (didintr)
2250 			comexit(exsig);		/* XXX besseres Konzept?!*/
2251 
2252 		if ((addr + cnt) > end)
2253 			cnt = end - addr;
2254 
2255 		if (meshpoints > 0) {
2256 			if (addr > next_point) {
2257 
2258 				msec = prstats_silent();
2259 				if ((msec - old_msec) == 0)		/* Avoid division by zero */
2260 					msec = old_msec + 1;
2261 				speed = ((addr - old_addr)/(1000.0/secsize)) / (0.001*(msec - old_msec));
2262 				if (do_factor) {
2263 					if (is_cdrom)
2264 						speed /= 176.400 * (secsize/2352.0);
2265 					else if (is_dvd)
2266 						speed /= 1385.0;
2267 					if (is_bd)
2268 						speed /= 4495.0;
2269 				}
2270 				error(_("addr: %8ld cnt: %ld"), addr, cnt);
2271 				printf("%8ld %8.2f\n", addr, speed);
2272 				if (plot)
2273 					flush();
2274 				error("\r");
2275 				next_point += secs_per_point;
2276 				old_addr = addr;
2277 				old_msec = msec;
2278 				i++;
2279 				if (meshpoints < 100)
2280 					flush();
2281 				else if (i % (meshpoints/100) == 0)
2282 					flush();
2283 			}
2284 		}
2285 		error(_("addr: %8ld cnt: %ld\r"), addr, cnt);
2286 
2287 		scgp->silent++;
2288 		if ((*rfunc)(scgp, rp, Sbuf, addr, cnt) < 0) {
2289 			scgp->silent--;
2290 			err = scgp->scmd->ux_errno;
2291 			if (quiet) {
2292 				error("\n");
2293 			} else if (scgp->silent == 0) {
2294 				scg_printerr(scgp);
2295 			}
2296 			errmsgno(err, _("Cannot read source disk\n"));
2297 
2298 			if (read_retry(scgp, Sbuf, addr, cnt, rfunc, rp) < 0) {
2299 				exargs.excode = -2;
2300 				goto out;
2301 			}
2302 		} else {
2303 			scgp->silent--;
2304 			if (scg_getresid(scgp)) {
2305 				error(_("\nresid: %d\n"), scg_getresid(scgp));
2306 				/*
2307 				 * If we use -ledc_ecc_dec for
2308 				 * correction, let the correction
2309 				 * happen on an upper layer, but make it an
2310 				 * error in case of DMA residual problems.
2311 				 */
2312 				if (!edc_corr)
2313 					goto out;
2314 			}
2315 		}
2316 		(*dfunc)(rp, Sbuf, addr, cnt);
2317 		if (filewrite(f, Sbuf, cnt * secsize) < 0) {
2318 			err = geterrno();
2319 			error("\n");
2320 			errmsgno(err, _("Cannot write '%s'\n"), filename);
2321 			exargs.excode = err;
2322 			break;
2323 		}
2324 	}
2325 	error(_("addr: %8ld"), addr);
2326 out:
2327 	error("\n");
2328 	msec = prstats();
2329 	if (msec == 0)		/* Avoid division by zero */
2330 		msec = 1;
2331 #ifdef	OOO
2332 	error(_("Read %.2f kB at %.1f kB/sec.\n"),
2333 		(double)(addr - start)/(1024.0/scgp->cap->c_bsize),
2334 		(double)((addr - start)/(1024.0/scgp->cap->c_bsize)) / (0.001*msec));
2335 #else
2336 	error(_("Read %.2f kB at %.1f kB/sec.\n"),
2337 		(double)(addr - start)/(1024.0/secsize),
2338 		(double)((addr - start)/(1024.0/secsize)) / (0.001*msec));
2339 #endif
2340 	print_bad();
2341 }
2342 
2343 LOCAL void
write_disk(scgp,parmp)2344 write_disk(scgp, parmp)
2345 	SCSI	*scgp;
2346 	parm_t	*parmp;
2347 {
2348 	char	filename[512];
2349 	char	*defname = "disk.out";
2350 	FILE	*f;
2351 	long	addr = 0L;
2352 	long	cnt;
2353 	long	amt;
2354 	long	end = 0L;
2355 	int	msec;
2356 	int	start;
2357 
2358 	if (is_suid)
2359 		comerrno(EX_BAD, _("Not root. Will not write in suid/priv mode\n"));
2360 
2361 	filename[0] = '\0';
2362 	if (read_capacity(scgp) >= 0) {
2363 		end = scgp->cap->c_baddr + 1;
2364 		print_capacity(scgp, stderr);
2365 	}
2366 
2367 	if (end <= 1)
2368 		end = 10000000;	/* Hack to write empty disks */
2369 
2370 	if (parmp) {
2371 		if (parmp->name)
2372 			defname = parmp->name;
2373 		error(_("Copy from file '%s' to SCSI (%d,%d,%d) disk\n"),
2374 					defname,
2375 					scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp));
2376 
2377 		addr = start = parmp->start;
2378 		if (parmp->end != -1 && parmp->end < end)
2379 			end = parmp->end;
2380 		cnt = Sbufsize / scgp->cap->c_bsize;
2381 		if (cnt > spt && spt > 0)
2382 			cnt = spt;
2383 	} else {
2384 		error(_("Copy from file to SCSI (%d,%d,%d) disk\n"),
2385 					scg_scsibus(scgp), scg_target(scgp), scg_lun(scgp));
2386 		error(_("Enter filename [%s]: "), defname); flush();
2387 		(void) getline(filename, sizeof (filename));
2388 		error(_("Notice: reading from file always starts at file offset 0.\n"));
2389 
2390 		getlong(_("Enter starting sector for copy:"), &addr, 0L, end-1);
2391 		start = addr;
2392 		cnt = end - addr;
2393 		getlong(_("Enter number of sectors to copy:"), &end, 1L, end);
2394 		end = addr + cnt;
2395 
2396 		cnt = Sbufsize / scgp->cap->c_bsize;
2397 		if (cnt > spt && spt > 0)
2398 			cnt = spt;
2399 		getlong(_("Enter number of sectors per copy:"), &cnt, 1L, cnt);
2400 /*		error("end:  %8ld\n", end);*/
2401 	}
2402 
2403 	if (filename[0] == '\0')
2404 		strncpy(filename, defname, sizeof (filename));
2405 	filename[sizeof (filename)-1] = '\0';
2406 	if (streql(filename, "-")) {
2407 		f = stdin;
2408 		setmode(STDIN_FILENO, O_BINARY);
2409 	} else if ((f = fileopen(filename, "rub")) == NULL)
2410 		comerr(_("Cannot open '%s'.\n"), filename);
2411 
2412 	error(_("end:  %8ld\n"), end);
2413 	if (gettimeofday(&starttime, (struct timezone *)0) < 0)
2414 		comerr(_("Cannot get start time\n"));
2415 
2416 	for (; addr < end; addr += cnt) {
2417 		if (didintr)
2418 			comexit(exsig);		/* XXX besseres Konzept?!*/
2419 
2420 		if ((addr + cnt) > end)
2421 			cnt = end - addr;
2422 
2423 		error(_("addr: %8ld cnt: %ld\r"), addr, cnt);
2424 
2425 		if ((amt = fileread(f, Sbuf, cnt * scgp->cap->c_bsize)) < 0)
2426 			comerr(_("Cannot read '%s'\n"), filename);
2427 		if (amt == 0)
2428 			break;
2429 		if ((amt / scgp->cap->c_bsize) < cnt)
2430 			cnt = amt / scgp->cap->c_bsize;
2431 		if (write_scsi(scgp, Sbuf, addr, cnt) < 0)
2432 			comerrno(scgp->scmd->ux_errno,
2433 					_("Cannot write destination disk\n"));
2434 	}
2435 	error(_("addr: %8ld\n"), addr);
2436 	msec = prstats();
2437 	if (msec == 0)		/* Avoid division by zero */
2438 		msec = 1;
2439 	error(_("Wrote %.2f kB at %.1f kB/sec.\n"),
2440 		(double)(addr - start)/(1024.0/scgp->cap->c_bsize),
2441 		(double)((addr - start)/(1024.0/scgp->cap->c_bsize)) / (0.001*msec));
2442 }
2443 
2444 LOCAL int
choice(n)2445 choice(n)
2446 	int	n;
2447 {
2448 #if	defined(HAVE_DRAND48)
2449 	extern	double	drand48 __PR((void));
2450 
2451 	return (drand48() * n);
2452 #else
2453 #	if	defined(HAVE_RAND)
2454 	extern	int	rand __PR((void));
2455 
2456 	return (rand() % n);
2457 #	else
2458 	return (0);
2459 #	endif
2460 #endif
2461 }
2462 
2463 LOCAL void
ra(scgp)2464 ra(scgp)
2465 	SCSI	*scgp;
2466 {
2467 /*	char	filename[512];*/
2468 	FILE	*f;
2469 /*	long	addr = 0L;*/
2470 /*	long	cnt;*/
2471 /*	long	end;*/
2472 /*	int	msec;*/
2473 /*	int	start;*/
2474 /*	int	err = 0;*/
2475 
2476 	select_secsize(scgp, 2352);
2477 	read_capacity(scgp);
2478 	print_capacity(scgp, stderr);
2479 	fillbytes(Sbuf, 50*2352, 0);
2480 	if (read_g1(scgp, Sbuf, 0, 50) < 0)
2481 		errmsg(_("read CD\n"));
2482 	f = fileopen("DDA", "wctb");
2483 /*	filewrite(f, Sbuf, 50 * 2352 - scg_getresid(scgp));*/
2484 	filewrite(f, Sbuf, 50 * 2352);
2485 	fclose(f);
2486 }
2487 
2488 #define	g5x_cdblen(cdb, len)	((cdb)->count[0] = ((len) >> 16L)& 0xFF,\
2489 				(cdb)->count[1] = ((len) >> 8L) & 0xFF,\
2490 				(cdb)->count[2] = (len) & 0xFF)
2491 
2492 EXPORT int
read_da(scgp,bp,addr,cnt,framesize,subcode)2493 read_da(scgp, bp, addr, cnt, framesize, subcode)
2494 	SCSI	*scgp;
2495 	caddr_t	bp;
2496 	long	addr;
2497 	int	cnt;
2498 	int	framesize;
2499 	int	subcode;
2500 {
2501 	register struct	scg_cmd	*scmd = scgp->scmd;
2502 
2503 	if (scgp->cap->c_bsize <= 0)
2504 		raisecond("capacity_not_set", 0L);
2505 
2506 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2507 	scmd->addr = bp;
2508 	scmd->size = cnt*framesize;
2509 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2510 	scmd->cdb_len = SC_G5_CDBLEN;
2511 	scmd->sense_len = CCS_SENSE_LEN;
2512 	scmd->cdb.g5_cdb.cmd = 0xd8;
2513 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2514 	g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
2515 	g5_cdblen(&scmd->cdb.g5_cdb, cnt);
2516 	scmd->cdb.g5_cdb.res10 = subcode;
2517 
2518 	scgp->cmdname = "read_da";
2519 
2520 	return (scg_cmd(scgp));
2521 }
2522 
2523 LOCAL int
read_sectors(scgp,p,addr,cnt)2524 read_sectors(scgp, p, addr, cnt)
2525 	SCSI	*scgp;
2526 	void	*p;
2527 	long	addr;
2528 	int	cnt;
2529 {
2530 	int	csize;
2531 	int	clusters;
2532 	int	rest;
2533 	int	i;
2534 	int	pos;
2535 
2536 	if (addr + cnt > scgp->cap->c_baddr + 1)
2537 		cnt = scgp->cap->c_baddr + 1 - addr;
2538 
2539 	csize = Sbufsize / (2352 + 294);
2540 	if (csize > spt && spt > 0)
2541 		csize = spt;
2542 	clusters = cnt / csize;
2543 	rest = cnt % csize;
2544 	pos = addr;
2545 
2546 	for (i = 0; i < clusters; i++) {
2547 		read_cd(scgp, p, pos, csize, 2352 + 294, 0xFA, 0);
2548 		pos += csize;
2549 	}
2550 
2551 	if (rest)
2552 		read_cd(scgp, p, pos, rest, 2352 + 294, 0xFA, 0);
2553 
2554 	return (csize * clusters + rest);
2555 }
2556 
2557 LOCAL int
read_dvd_sectors(scgp,p,addr,cnt)2558 read_dvd_sectors(scgp, p, addr, cnt)
2559 	SCSI	*scgp;
2560 	void	*p;
2561 	long	addr;
2562 	int	cnt;
2563 {
2564 	int	csize;
2565 	int	clusters;
2566 	int	rest;
2567 	int	i;
2568 	int	pos;
2569 
2570 	if (addr + cnt > scgp->cap->c_baddr + 1)
2571 		cnt = scgp->cap->c_baddr + 1 - addr;
2572 
2573 	csize = Sbufsize / 2048;
2574 	if (csize > spt && spt > 0)
2575 		csize = spt;
2576 	clusters = cnt / csize;
2577 	rest = cnt % csize;
2578 	pos = addr;
2579 
2580 	for (i = 0; i < clusters; i++) {
2581 		read_g1(scgp, p, pos, csize);
2582 		pos += csize;
2583 	}
2584 
2585 	if (rest)
2586 		read_g1(scgp, p, pos, rest);
2587 
2588 	return (csize * clusters + rest);
2589 }
2590 
2591 LOCAL BOOL
mmc_isplextor(scgp)2592 mmc_isplextor(scgp)
2593 	SCSI	*scgp;
2594 {
2595 	if (scgp->inq != NULL &&
2596 			strncmp(scgp->inq->inq_vendor_info, "PLEXTOR", 7) == 0) {
2597 		return (TRUE);
2598 	}
2599 	return (FALSE);
2600 }
2601 
2602 LOCAL int
plextor_init_cx_scan(scgp)2603 plextor_init_cx_scan(scgp)
2604 	SCSI	*scgp;
2605 {
2606 	register struct	scg_cmd	*scmd = scgp->scmd;
2607 
2608 	if (!mmc_isplextor(scgp))
2609 		return (-1);
2610 
2611 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2612 
2613 	scmd->size = 0;
2614 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2615 	scmd->cdb_len = SC_G5_CDBLEN;
2616 	scmd->sense_len = CCS_SENSE_LEN;
2617 	scmd->cdb.g5_cdb.cmd = 0xEA;
2618 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2619 	scmd->cdb.cmd_cdb[1] |= 0x15;
2620 	scmd->cdb.cmd_cdb[3] = 0x01;
2621 
2622 	scgp->cmdname = "plextor_init_cx_scan";
2623 
2624 	return (scg_cmd(scgp));
2625 }
2626 
2627 LOCAL int
plextor_init_pi8_scan(scgp)2628 plextor_init_pi8_scan(scgp)
2629 	SCSI	*scgp;
2630 {
2631 	register struct	scg_cmd	*scmd = scgp->scmd;
2632 
2633 	if (!mmc_isplextor(scgp))
2634 		return (-1);
2635 
2636 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2637 
2638 	scmd->size = 0;
2639 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2640 	scmd->cdb_len = SC_G5_CDBLEN;
2641 	scmd->sense_len = CCS_SENSE_LEN;
2642 	scmd->cdb.g5_cdb.cmd = 0xEA;
2643 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2644 	scmd->cdb.cmd_cdb[1] |= 0x15;
2645 	scmd->cdb.cmd_cdb[8] = 0x08;
2646 	scmd->cdb.cmd_cdb[9] = 0x10;
2647 
2648 	scgp->cmdname = "plextor_init_pi8_scan";
2649 
2650 	return (scg_cmd(scgp));
2651 }
2652 
2653 LOCAL int
plextor_init_pif_scan(scgp)2654 plextor_init_pif_scan(scgp)
2655 	SCSI	*scgp;
2656 {
2657 	register struct	scg_cmd	*scmd = scgp->scmd;
2658 
2659 	if (!mmc_isplextor(scgp))
2660 		return (-1);
2661 
2662 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2663 
2664 	scmd->size = 0;
2665 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2666 	scmd->cdb_len = SC_G5_CDBLEN;
2667 	scmd->sense_len = CCS_SENSE_LEN;
2668 	scmd->cdb.g5_cdb.cmd = 0xEA;
2669 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2670 	scmd->cdb.cmd_cdb[1] |= 0x15;
2671 	scmd->cdb.cmd_cdb[8] = 0x01;
2672 	scmd->cdb.cmd_cdb[9] = 0x12;
2673 
2674 	scgp->cmdname = "plextor_init_pif_scan";
2675 
2676 	return (scg_cmd(scgp));
2677 }
2678 
2679 LOCAL int
nec_init_cx_scan(scgp)2680 nec_init_cx_scan(scgp)
2681 	SCSI	*scgp;
2682 {
2683 	register struct	scg_cmd	*scmd = scgp->scmd;
2684 	int		ret;
2685 
2686 	/*
2687 	 * initialize scan mode
2688 	 */
2689 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2690 
2691 	scmd->size = 0;
2692 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2693 	scmd->cdb_len = SC_G5_CDBLEN;
2694 	scmd->sense_len = CCS_SENSE_LEN;
2695 	scmd->cdb.g5_cdb.cmd = 0xF3;
2696 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2697 	scmd->cdb.cmd_cdb[1] |= 0x01;
2698 
2699 	scgp->cmdname = "nec_init_cx_scan";
2700 
2701 	ret = scg_cmd(scgp);
2702 	if (ret < 0)
2703 		return (ret);
2704 
2705 	/*
2706 	 * set scan interval = 75 sectors
2707 	 */
2708 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2709 	scmd->size = 0;
2710 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2711 	scmd->cdb_len = SC_G5_CDBLEN;
2712 	scmd->sense_len = CCS_SENSE_LEN;
2713 	scmd->cdb.g5_cdb.cmd = 0xF3;
2714 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2715 	scmd->cdb.cmd_cdb[1] |= 0x02;
2716 	scmd->cdb.cmd_cdb[8] = 75;
2717 
2718 	scgp->cmdname = "nec_set_cx_scan_interval";
2719 
2720 	return (scg_cmd(scgp));
2721 }
2722 
2723 LOCAL int
plextor_scan_one_interval(scgp,pe,addr,p)2724 plextor_scan_one_interval(scgp, pe, addr, p)
2725 	SCSI*		scgp;
2726 	cxerror_t	*pe;
2727 	long		addr;
2728 	void		*p;
2729 {
2730 	int	i;
2731 
2732 	i = read_sectors(scgp, p, addr, 75);
2733 	plextor_read_cx_values(scgp, pe, FALSE);
2734 
2735 	return (addr + i);
2736 }
2737 
2738 LOCAL int
plextor_scan_one_dvd_interval(scgp,pe,addr,p)2739 plextor_scan_one_dvd_interval(scgp, pe, addr, p)
2740 	SCSI*		scgp;
2741 	cxerror_t	*pe;
2742 	long		addr;
2743 	void		*p;
2744 {
2745 	int	i;
2746 
2747 	if (pifscan)
2748 		i = read_dvd_sectors(scgp, p, addr, 16);
2749 	else
2750 		i = read_dvd_sectors(scgp, p, addr, 16*8);
2751 	plextor_read_cx_values(scgp, pe, TRUE);
2752 
2753 	return (addr + i);
2754 }
2755 
2756 /* ARGSUSED */
2757 LOCAL int
nec_scan_one_interval(scgp,pe,addr,p)2758 nec_scan_one_interval(scgp, pe, addr, p)
2759 	SCSI		*scgp;
2760 	cxerror_t	*pe;
2761 	long		addr;
2762 	void		*p;
2763 {
2764 	register struct	scg_cmd	*scmd = scgp->scmd;
2765 	Uchar		data[8];
2766 	int		ret;
2767 
2768 	fillbytes(data, sizeof (data), '\0');
2769 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2770 	scmd->size = 8;
2771 	scmd->addr = (caddr_t)data;
2772 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2773 	scmd->cdb_len = SC_G5_CDBLEN;
2774 	scmd->sense_len = CCS_SENSE_LEN;
2775 	scmd->cdb.g5_cdb.cmd = 0xF3;
2776 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2777 	scmd->cdb.cmd_cdb[1] |= 0x03;
2778 
2779 	scgp->cmdname = "nec_set_cx_scan_interval";
2780 
2781 	ret = scg_cmd(scgp);
2782 
2783 	if (ret < 0)
2784 		return (ret);
2785 
2786 	pe->c1_errors = a_to_u_2_byte(data+4);
2787 	pe->c2_errors = a_to_u_2_byte(data+6);
2788 	pe->cu_errors = 0;
2789 
2790 	return ((int)data[1] * 4500 + (int)data[2] * 75 + (int)data[3]);
2791 }
2792 
2793 LOCAL int
plextor_end_scan(scgp)2794 plextor_end_scan(scgp)
2795 	SCSI	*scgp;
2796 {
2797 	register struct	scg_cmd	*scmd = scgp->scmd;
2798 
2799 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2800 
2801 	scmd->size = 0;
2802 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2803 	scmd->cdb_len = SC_G5_CDBLEN;
2804 	scmd->sense_len = CCS_SENSE_LEN;
2805 	scmd->cdb.g5_cdb.cmd = 0xEA;
2806 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2807 	scmd->cdb.cmd_cdb[1] |= 0x17;
2808 
2809 	scgp->cmdname = "plextor_end_scan";
2810 
2811 	return (scg_cmd(scgp));
2812 }
2813 
2814 LOCAL int
nec_end_scan(scgp)2815 nec_end_scan(scgp)
2816 	SCSI	*scgp;
2817 {
2818 	register struct	scg_cmd	*scmd = scgp->scmd;
2819 	char		data[8];
2820 
2821 	fillbytes(data, sizeof (data), '\0');
2822 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2823 
2824 	scmd->addr = data;
2825 	scmd->size = 8;
2826 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2827 	scmd->cdb_len = SC_G5_CDBLEN;
2828 	scmd->sense_len = CCS_SENSE_LEN;
2829 	scmd->cdb.g5_cdb.cmd = 0xF3;
2830 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2831 	scmd->cdb.cmd_cdb[1] |= 0x0F;
2832 
2833 	scgp->cmdname = "nec_end_cx_scan";
2834 
2835 	return (scg_cmd(scgp));
2836 }
2837 
2838 LOCAL int
plextor_read_cx_values(scgp,pe,dopi)2839 plextor_read_cx_values(scgp, pe, dopi)
2840 	SCSI		*scgp;
2841 	cxerror_t	*pe;
2842 	BOOL		dopi;
2843 {
2844 	register struct	scg_cmd	*scmd = scgp->scmd;
2845 	char		data[52];
2846 	int		ret;
2847 
2848 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2849 	fillbytes(data, sizeof (data), '\0');
2850 
2851 	scmd->addr = data;
2852 	scmd->size = dopi ? 52:0x1A;
2853 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2854 	scmd->cdb_len = SC_G5_CDBLEN;
2855 	scmd->sense_len = CCS_SENSE_LEN;
2856 
2857 	scmd->cdb.g5_cdb.cmd = 0xEA;
2858 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2859 	scmd->cdb.cmd_cdb[1] |= 0x16;
2860 	scmd->cdb.cmd_cdb[2] = 0x01;
2861 	scmd->cdb.cmd_cdb[10] = dopi ? 52:0x1A;
2862 
2863 	scgp->cmdname = "plextor_read_cx_values";
2864 
2865 	ret = scg_cmd(scgp);
2866 	if (ret < 0) {
2867 		return (ret);
2868 	}
2869 
2870 	pe->c1_errors = a_to_u_2_byte(data+16) +	/* E11 ??? */
2871 			a_to_u_2_byte(data+14) +	/* E21 ??? */
2872 			a_to_u_2_byte(data+12);		/* E31 ??? */
2873 	pe->c2_errors = a_to_u_2_byte(data+22);
2874 	pe->cu_errors = a_to_u_2_byte(data+20);
2875 
2876 	pe->pi_errors = a_to_u_4_byte(data+36);
2877 
2878 	return (ret);
2879 }
2880 
2881 EXPORT int
read_cd(scgp,bp,addr,cnt,framesize,data,subch)2882 read_cd(scgp, bp, addr, cnt, framesize, data, subch)
2883 	SCSI	*scgp;
2884 	caddr_t	bp;
2885 	long	addr;
2886 	int	cnt;
2887 	int	framesize;
2888 	int	data;
2889 	int	subch;
2890 {
2891 	register struct	scg_cmd	*scmd = scgp->scmd;
2892 
2893 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2894 	scmd->addr = bp;
2895 	scmd->size = cnt*framesize;
2896 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2897 	scmd->cdb_len = SC_G5_CDBLEN;
2898 	scmd->sense_len = CCS_SENSE_LEN;
2899 	scmd->cdb.g5_cdb.cmd = 0xBE;
2900 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
2901 	scmd->cdb.g5_cdb.res = 0;	/* expected sector type field ALL */
2902 	g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
2903 	g5x_cdblen(&scmd->cdb.g5_cdb, cnt);
2904 
2905 	scmd->cdb.g5_cdb.count[3] = data & 0xFF;
2906 	scmd->cdb.g5_cdb.res10 = subch & 0x07;
2907 
2908 	scgp->cmdname = "read_cd";
2909 
2910 	return (scg_cmd(scgp));
2911 }
2912 
2913 LOCAL void
oldmode(scgp,errp,retrp)2914 oldmode(scgp, errp, retrp)
2915 	SCSI	*scgp;
2916 	int	*errp;
2917 	int	*retrp;
2918 {
2919 	Uchar	mode[0x100];
2920 	Uchar	cmode[0x100];
2921 	Uchar	*p;
2922 	int	i;
2923 	int	len;
2924 
2925 	fillbytes(mode, sizeof (mode), '\0');
2926 	fillbytes(cmode, sizeof (cmode), '\0');
2927 
2928 	if (!get_mode_params(scgp, 0x01, _("CD error recovery parameter"),
2929 			mode, (Uchar *)0, (Uchar *)cmode, (Uchar *)0, &len)) {
2930 		return;
2931 	}
2932 	if (xdebug)
2933 		scg_prbytes(_("Mode Sense Data"), mode, len);
2934 
2935 	mode[0] = 0;
2936 	mode[2] = 0; /* ??? ist manchmal 0x80 */
2937 	p = mode;
2938 	p += mode[3] + 4;
2939 	*p &= 0x3F;
2940 
2941 	if (xdebug)
2942 		scg_prbytes(_("Mode page 1:"), p, 0x10);
2943 
2944 	i = p[2];
2945 	if (errp != NULL)
2946 		*errp = i;
2947 
2948 	i = p[3];
2949 	if (retrp != NULL)
2950 		*retrp = i;
2951 }
2952 
2953 LOCAL void
domode(scgp,err,retr)2954 domode(scgp, err, retr)
2955 	SCSI	*scgp;
2956 	int	err;
2957 	int	retr;
2958 {
2959 	Uchar	mode[0x100];
2960 	Uchar	cmode[0x100];
2961 	Uchar	*p;
2962 	int	i;
2963 	int	len;
2964 
2965 	fillbytes(mode, sizeof (mode), '\0');
2966 	fillbytes(cmode, sizeof (cmode), '\0');
2967 
2968 	if (!get_mode_params(scgp, 0x01, _("CD error recovery parameter"),
2969 			mode, (Uchar *)0, (Uchar *)cmode, (Uchar *)0, &len)) {
2970 		return;
2971 	}
2972 	if (xdebug || (err == -1 && retr == -1)) {
2973 		scg_prbytes(_("Mode Sense Data"), mode, len);
2974 	}
2975 
2976 	mode[0] = 0;
2977 	mode[2] = 0; /* ??? ist manchmal 0x80 */
2978 	p = mode;
2979 	p += mode[3] + 4;
2980 	*p &= 0x3F;
2981 
2982 	if (xdebug || (err == -1 && retr == -1))
2983 		scg_prbytes(_("Mode page 1:"), p, 0x10);
2984 
2985 	i = p[2];
2986 	if (err == -1) {
2987 		getint(_("Error handling? "), &i, 0, 255);
2988 		p[2] = i;
2989 	} else {
2990 		if (xdebug)
2991 			error(_("Error handling set from %02X to %02X\n"),
2992 		p[2], err);
2993 		p[2] = err;
2994 	}
2995 
2996 	i = p[3];
2997 	if (retr == -1) {
2998 		getint(_("Retry count? "), &i, 0, 255);
2999 		p[3] = i;
3000 	} else {
3001 		if (xdebug)
3002 			error(_("Retry count set from %d to %d\n"),
3003 		p[3] & 0xFF, retr);
3004 		p[3] = retr;
3005 	}
3006 
3007 	if (xdebug || (err == -1 && retr == -1))
3008 		scg_prbytes(_("Mode Select Data"), mode, len);
3009 	mode_select(scgp, mode, len, 0, scgp->inq->data_format >= 2);
3010 }
3011 
3012 
3013 /*--------------------------------------------------------------------------*/
3014 LOCAL	void	qpto96		__PR((Uchar *sub, Uchar *subq, int dop));
3015 /*EXPORT	void	qpto96		__PR((Uchar *sub, Uchar *subq, int dop));*/
3016 /*
3017  * Q-Sub auf 96 Bytes bl�hen und P-Sub addieren
3018  *
3019  * OUT: sub, IN: subqptr
3020  */
3021 LOCAL void
3022 /*EXPORT void*/
qpto96(sub,subqptr,dop)3023 qpto96(sub, subqptr, dop)
3024 	Uchar	*sub;
3025 	Uchar	*subqptr;
3026 	int	dop;
3027 {
3028 	Uchar	tmp[16];
3029 	Uchar	*p;
3030 	int	c;
3031 	int	i;
3032 
3033 	if (subqptr == sub) {
3034 		movebytes(subqptr, tmp, 12);
3035 		subqptr = tmp;
3036 	}
3037 	fillbytes(sub, 96, '\0');
3038 
3039 	/* CSTYLED */
3040 	if (dop) for (i = 0, p = sub; i < 96; i++) {
3041 		*p++ |= 0x80;
3042 	}
3043 	for (i = 0, p = sub; i < 12; i++) {
3044 		c = subqptr[i] & 0xFF;
3045 /*printf("%02X\n", c);*/
3046 		if (c & 0x80)
3047 			*p++ |= 0x40;
3048 		else
3049 			p++;
3050 		if (c & 0x40)
3051 			*p++ |= 0x40;
3052 		else
3053 			p++;
3054 		if (c & 0x20)
3055 			*p++ |= 0x40;
3056 		else
3057 			p++;
3058 		if (c & 0x10)
3059 			*p++ |= 0x40;
3060 		else
3061 			p++;
3062 		if (c & 0x08)
3063 			*p++ |= 0x40;
3064 		else
3065 			p++;
3066 		if (c & 0x04)
3067 			*p++ |= 0x40;
3068 		else
3069 			p++;
3070 		if (c & 0x02)
3071 			*p++ |= 0x40;
3072 		else
3073 			p++;
3074 		if (c & 0x01)
3075 			*p++ |= 0x40;
3076 		else
3077 			p++;
3078 	}
3079 }
3080 
3081 /*--------------------------------------------------------------------------*/
3082 
3083 LOCAL void
ovtime(scgp)3084 ovtime(scgp)
3085 	SCSI	*scgp;
3086 {
3087 	register int	i;
3088 
3089 	scgp->silent++;
3090 	(void) test_unit_ready(scgp);
3091 	scgp->silent--;
3092 	if (test_unit_ready(scgp) < 0)
3093 		return;
3094 
3095 	printf(_("Doing 1000 'TEST UNIT READY' operations.\n"));
3096 
3097 	if (gettimeofday(&starttime, (struct timezone *)0) < 0)
3098 		comerr(_("Cannot get start time\n"));
3099 
3100 	for (i = 1000; --i >= 0; ) {
3101 		(void) test_unit_ready(scgp);
3102 
3103 		if (didintr)
3104 			return;
3105 	}
3106 
3107 	prstats();
3108 
3109 	/*
3110 	 * ATAPI drives do not like seek_g0()
3111 	 */
3112 	scgp->silent++;
3113 	i = seek_g0(scgp, 0L);
3114 	scgp->silent--;
3115 
3116 	if (i >= 0) {
3117 		printf(_("Doing 1000 'SEEK_G0 (0)' operations.\n"));
3118 
3119 		if (gettimeofday(&starttime, (struct timezone *)0) < 0)
3120 			comerr(_("Cannot get start time\n"));
3121 
3122 		for (i = 1000; --i >= 0; ) {
3123 			(void) seek_g0(scgp, 0L);
3124 
3125 			if (didintr)
3126 				return;
3127 		}
3128 
3129 		prstats();
3130 	}
3131 
3132 	scgp->silent++;
3133 	i = seek_g1(scgp, 0L);
3134 	scgp->silent--;
3135 	if (i < 0)
3136 		return;
3137 
3138 	printf(_("Doing 1000 'SEEK_G1 (0)' operations.\n"));
3139 
3140 	if (gettimeofday(&starttime, (struct timezone *)0) < 0)
3141 		comerr(_("Cannot get start time\n"));
3142 
3143 	for (i = 1000; --i >= 0; ) {
3144 		(void) seek_g1(scgp, 0L);
3145 
3146 		if (didintr)
3147 			return;
3148 	}
3149 
3150 	prstats();
3151 }
3152 
3153 #define	BAD_INC		16
3154 long	*badsecs;
3155 int	nbad;
3156 int	maxbad;
3157 
3158 LOCAL void
add_bad(addr)3159 add_bad(addr)
3160 	long	addr;
3161 {
3162 	if (maxbad == 0) {
3163 		maxbad = BAD_INC;
3164 		badsecs = malloc(maxbad * sizeof (long));
3165 		if (badsecs == NULL)
3166 			comerr(_("No memory for bad sector list.\n"));
3167 	}
3168 	if (nbad >= maxbad) {
3169 		maxbad += BAD_INC;
3170 		badsecs = realloc(badsecs, maxbad * sizeof (long));
3171 		if (badsecs == NULL)
3172 			comerr(_("No memory to grow bad sector list.\n"));
3173 	}
3174 	badsecs[nbad++] = addr;
3175 }
3176 
3177 LOCAL void
print_bad()3178 print_bad()
3179 {
3180 	int	i;
3181 
3182 	if (nbad == 0)
3183 		return;
3184 
3185 	error(_("Max corected retry count was %d (limited to %d).\n"), maxtry, retries);
3186 	error(_("The following %d sector(s) could not be read correctly:\n"), nbad);
3187 	for (i = 0; i < nbad; i++)
3188 		error("%ld\n", badsecs[i]);
3189 	if (edc_corr)
3190 		error(_("Corrected by EDC: %d\n"), edc_OK);
3191 }
3192 
3193 LOCAL void
priv_warn(what,msg)3194 priv_warn(what, msg)
3195 	const char	*what;
3196 	const char	*msg;
3197 {
3198 	errmsgno(EX_BAD, "Insufficient '%s' privileges. %s\n", what, msg);
3199 }
3200