1 /* @(#)drv_dvdplus.c	1.65 12/03/16 Copyright 2003-2012 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)drv_dvdplus.c	1.65 12/03/16 Copyright 2003-2012 J. Schilling";
6 #endif
7 /*
8  *	Copyright (c) 2003-2012 J. Schilling
9  */
10 /*
11  * The contents of this file are subject to the terms of the
12  * Common Development and Distribution License, Version 1.0 only
13  * (the "License").  You may not use this file except in compliance
14  * with the License.
15  *
16  * See the file CDDL.Schily.txt in this distribution for details.
17  *
18  * When distributing Covered Code, include this CDDL HEADER in each
19  * file and include the License file CDDL.Schily.txt from this distribution.
20  */
21 
22 /*
23  *	DVD+R/RW device implementation for
24  *	SCSI-3/mmc-3 conforming drives
25  *
26  * XXX Aktualisieren:
27  *		Check recovery		- DUMMY
28  *		Load Media		- OK
29  *		Get Disktype		- Disk Status & Size (read ATIP -> DVD structure)
30  *		Check Session ??	- Nicht vorhanden
31  *		Check Disk size		- Nach Status & size + Next wr. Addr.
32  *		Set Speed/Dummy		- Speed auf DVD -> dummy
33  *		Open Session		- Set Write Parameter & ??? -> DAO
34  *		LOOP
35  *			Open Track	- Set Write Parameter ???
36  *			Get Next wr. Addr.	-> DUMMY "0" ???
37  *			Write Track Data	OK
38  *			Close Track	- Flush Cache -> DUMMY
39  *		END
40  *		Fixate			- Close Track/Session -> Flush Cache
41  *		Unload Media		- OK
42  *
43  *	Verbose levels:
44  *			0		silent
45  *			1		print laser log & track sizes
46  *			2		print disk info & write parameters
47  *			3		print log pages & dvd structure
48  *
49  *	Copyright (c) 2003-2009 J. Schilling
50  */
51 /*
52  * The contents of this file are subject to the terms of the
53  * Common Development and Distribution License, Version 1.0 only
54  * (the "License").  You may not use this file except in compliance
55  * with the License.
56  *
57  * See the file CDDL.Schily.txt in this distribution for details.
58  *
59  * When distributing Covered Code, include this CDDL HEADER in each
60  * file and include the License file CDDL.Schily.txt from this distribution.
61  */
62 
63 /*#define	DVDPLUS_DEBUG*/
64 #ifndef	DEBUG
65 #define	DEBUG
66 #endif
67 #include <schily/mconfig.h>
68 
69 #include <schily/stdio.h>
70 #include <schily/stdlib.h>
71 #include <schily/unistd.h>	/* Include sys/types.h to make off_t available */
72 #include <schily/standard.h>
73 #include <schily/string.h>
74 #include <schily/time.h>
75 
76 #include <schily/utypes.h>
77 #include <schily/btorder.h>
78 #include <schily/intcvt.h>
79 #include <schily/schily.h>
80 #include <schily/nlsdefs.h>
81 
82 #include <scg/scgcmd.h>
83 #include <scg/scsidefs.h>
84 #include <scg/scsireg.h>
85 #include <scg/scsitransp.h>
86 
87 #include "scsimmc.h"
88 #include "scsilog.h"
89 #include "mmcvendor.h"
90 #include "cdrecord.h"
91 
92 
93 extern	char	*driveropts;
94 
95 extern	int	lverbose;
96 extern	int	xdebug;
97 
98 #define	strbeg(s1, s2)	(strstr((s2), (s1)) == (s2))
99 
100 LOCAL	cdr_t	*identify_dvdplus	__PR((SCSI *scgp, cdr_t *, struct scsi_inquiry *));
101 LOCAL	int	attach_dvdplus		__PR((SCSI *scgp, cdr_t *));
102 LOCAL	void	di_to_dstat		__PR((struct disk_info *dip, dstat_t *dsp));
103 LOCAL	int	init_dvdplus		__PR((SCSI *scgp, cdr_t *dp));
104 LOCAL	int	getdisktype_dvdplus	__PR((SCSI *scgp, cdr_t *dp));
105 LOCAL	int	prdiskstatus_dvdplus	__PR((SCSI *scgp, cdr_t *dp));
106 LOCAL	int	speed_select_dvdplus	__PR((SCSI *scgp, cdr_t *dp, int *speedp));
107 LOCAL	int	next_wr_addr_dvdplusrw	__PR((SCSI *scgp, track_t *trackp, long *ap));
108 LOCAL	int	next_wr_addr_dvdplusr	__PR((SCSI *scgp, track_t *trackp, long *ap));
109 LOCAL	int	open_track_dvdplus	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
110 LOCAL	long	rzone_size		__PR((track_t *trackp));
111 LOCAL	int	close_track_dvdplus	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
112 /*LOCAL	int	open_session_dvdplus	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));*/
113 LOCAL	int	fixate_dvdplusrw	__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
114 LOCAL	int	fixate_dvdplusr		__PR((SCSI *scgp, cdr_t *dp, track_t *trackp));
115 LOCAL	BOOL	dvdplus_ricohbased	__PR((SCSI *scgp));
116 LOCAL	int	blank_dvdplus		__PR((SCSI *scgp, cdr_t *dp, long addr, int blanktype));
117 LOCAL	int	format_dvdplus		__PR((SCSI *scgp, cdr_t *dp, int fmtflags));
118 LOCAL	int	waitformat		__PR((SCSI *scgp, int secs));
119 LOCAL	int	stats_dvdplus		__PR((SCSI *scgp, cdr_t *dp));
120 
121 EXPORT	int	format_unit		__PR((SCSI *scgp,
122 						void *fmt, int length,
123 						int list_format, int dgdl,
124 						int interlv, int pattern, int timeout));
125 LOCAL	int	set_p_layerbreak	__PR((SCSI *scgp, long tsize, Int32_t lbreak));
126 
127 #define	CHANGE_SETTING	1
128 #define	DVD_PLUS_R	2
129 #define	DC_ERASE	4
130 LOCAL	int	ricoh_dvdsetting	__PR((SCSI *scgp, int erase_size, int flags, int immed));
131 
132 #ifdef	__needed__
133 LOCAL	int	dummy_plextor		__PR((SCSI *scgp, int modecode));
134 #endif
135 
136 /*
137  * SCSI-3/mmc-3 conformant DVD+R or DVD+RW writer
138  * Checks the current medium and then returns either
139  * cdr_dvdplusr or cdr_dvdplusrw
140  */
141 cdr_t	cdr_dvdplus = {
142 	0, 0, 0,
143 	CDR_DVD|CDR_SWABAUDIO,
144 	CDR2_NOCD,
145 	CDR_CDRW_ALL,
146 	WM_NONE,
147 	1000, 1000,
148 	"mmc_dvdplus",
149 	"generic SCSI-3/mmc-3 DVD+R/DVD+RW driver (checks media)",
150 	0,
151 	(dstat_t *)0,
152 	identify_dvdplus,
153 	attach_dvdplus,
154 	(int(*)__PR((SCSI *scgp, cdr_t *)))cmd_ill,	/* init */
155 	drive_getdisktype,
156 	no_diskstatus,
157 	scsi_load,
158 	scsi_unload,
159 	read_buff_cap,
160 	cmd_dummy,					/* recovery_needed */
161 	(int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy,	/* recover	*/
162 	(int(*)__PR((SCSI *scgp, cdr_t *, int *)))cmd_dummy,		/* Speed */
163 	select_secsize,
164 	(int(*)__PR((SCSI *scgp, track_t *, long *)))cmd_ill,	/* next_wr_addr	 */
165 	(int(*)__PR((SCSI *, Ulong)))cmd_ill,			/* reserve_track */
166 	scsi_cdr_write,
167 	(int(*)__PR((track_t *, void *, BOOL)))cmd_dummy,	/* gen_cue */
168 	no_sendcue,
169 	(int(*)__PR((SCSI *, cdr_t *, track_t *)))cmd_dummy,		/* leadin */
170 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy,	/* open track */
171 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy,	/* close track */
172 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy,	/* open session */
173 	cmd_dummy,					/* close session */
174 	cmd_dummy,					/* abort */
175 	read_session_offset,
176 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy,	/* fixation */
177 	cmd_dummy,					/* stats	*/
178 	blank_dummy,
179 	format_dummy,
180 	(int(*)__PR((SCSI *, caddr_t, int, int)))NULL,	/* no OPC	*/
181 	cmd_dummy,					/* opt1		*/
182 	cmd_dummy,					/* opt2		*/
183 };
184 
185 /*
186  * SCSI-3/mmc-3 conformant DVD+R writer
187  */
188 cdr_t	cdr_dvdplusr = {
189 	0, 0, 0,
190 	CDR_DVD|CDR_SWABAUDIO,
191 	CDR2_NOCD,
192 	CDR_CDRW_ALL,
193 	WM_SAO,
194 	1000, 1000,
195 	"mmc_dvdplusr",
196 	"generic SCSI-3/mmc-3 DVD+R driver",
197 	0,
198 	(dstat_t *)0,
199 	identify_dvdplus,
200 	attach_dvdplus,
201 	init_dvdplus,
202 	getdisktype_dvdplus,
203 	prdiskstatus_dvdplus,
204 	scsi_load,
205 	scsi_unload,
206 	read_buff_cap,
207 	cmd_dummy,					/* recovery_needed */
208 	(int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy,	/* recover	*/
209 	speed_select_dvdplus,
210 	select_secsize,
211 	next_wr_addr_dvdplusr,
212 	(int(*)__PR((SCSI *, Ulong)))cmd_ill,		/* reserve_track */
213 	scsi_cdr_write,
214 	(int(*)__PR((track_t *, void *, BOOL)))cmd_dummy,	/* gen_cue */
215 	no_sendcue,
216 	(int(*)__PR((SCSI *, cdr_t *, track_t *)))cmd_dummy, /* leadin */
217 	open_track_dvdplus,
218 	close_track_dvdplus,
219 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy,	/* open session */
220 	cmd_dummy,					/* close session */
221 	cmd_dummy,					/* abort	*/
222 	read_session_offset,
223 	fixate_dvdplusr,
224 	stats_dvdplus,
225 	blank_dvdplus,
226 	format_dummy,
227 	(int(*)__PR((SCSI *, caddr_t, int, int)))NULL,	/* no OPC	*/
228 	cmd_dummy,					/* opt1		*/
229 	cmd_dummy,					/* opt2		*/
230 };
231 
232 /*
233  * SCSI-3/mmc-3 conformant DVD+RW writer
234  */
235 cdr_t	cdr_dvdplusrw = {
236 	0, 0, 0,
237 	CDR_DVD|CDR_SWABAUDIO,
238 	CDR2_NOCD,
239 	CDR_CDRW_ALL,
240 	WM_SAO,
241 	1000, 1000,
242 	"mmc_dvdplusrw",
243 	"generic SCSI-3/mmc-3 DVD+RW driver",
244 	0,
245 	(dstat_t *)0,
246 	identify_dvdplus,
247 	attach_dvdplus,
248 	init_dvdplus,
249 	getdisktype_dvdplus,
250 	prdiskstatus_dvdplus,
251 	scsi_load,
252 	scsi_unload,
253 	read_buff_cap,
254 	cmd_dummy,					/* recovery_needed */
255 	(int(*)__PR((SCSI *, cdr_t *, int)))cmd_dummy,	/* recover	*/
256 	speed_select_dvdplus,
257 	select_secsize,
258 	next_wr_addr_dvdplusrw,
259 	(int(*)__PR((SCSI *, Ulong)))cmd_ill,		/* reserve_track */
260 	scsi_cdr_write,
261 	(int(*)__PR((track_t *, void *, BOOL)))cmd_dummy,	/* gen_cue */
262 	no_sendcue,
263 	(int(*)__PR((SCSI *, cdr_t *, track_t *)))cmd_dummy, /* leadin */
264 	open_track_dvdplus,
265 	close_track_dvdplus,
266 	(int(*)__PR((SCSI *scgp, cdr_t *, track_t *)))cmd_dummy,	/* open session */
267 	cmd_dummy,					/* close session */
268 	cmd_dummy,					/* abort	*/
269 	read_session_offset,
270 	fixate_dvdplusrw,
271 	stats_dvdplus,
272 	blank_dvdplus,
273 	format_dvdplus,
274 	(int(*)__PR((SCSI *, caddr_t, int, int)))NULL,	/* no OPC	*/
275 	cmd_dummy,					/* opt1		*/
276 	cmd_dummy,					/* opt2		*/
277 };
278 
279 LOCAL cdr_t *
identify_dvdplus(scgp,dp,ip)280 identify_dvdplus(scgp, dp, ip)
281 	SCSI			*scgp;
282 	cdr_t			*dp;
283 	struct scsi_inquiry	*ip;
284 {
285 	Uchar	mode[0x100];
286 	struct	cd_mode_page_2A *mp;
287 	int	profile;
288 
289 	if (ip->type != INQ_WORM && ip->type != INQ_ROMD)
290 		return ((cdr_t *)0);
291 
292 	allow_atapi(scgp, TRUE); /* Try to switch to 10 byte mode cmds */
293 
294 	scgp->silent++;
295 	mp = mmc_cap(scgp, mode); /* Get MMC capabilities */
296 	scgp->silent--;
297 	if (mp == NULL)
298 		return (NULL);	/* Pre SCSI-3/mmc drive		*/
299 
300 	/*
301 	 * At this point we know that we have a SCSI-3/mmc compliant drive.
302 	 * Unfortunately ATAPI drives violate the SCSI spec in returning
303 	 * a response data format of '1' which from the SCSI spec would
304 	 * tell us not to use the "PF" bit in mode select. As ATAPI drives
305 	 * require the "PF" bit to be set, we 'correct' the inquiry data.
306 	 *
307 	 * XXX xxx_identify() should not have any side_effects ??
308 	 */
309 	if (ip->data_format < 2)
310 		ip->data_format = 2;
311 
312 	profile = get_curprofile(scgp);
313 	if (xdebug)
314 		printf(_("Current profile: 0x%04X\n"), profile);
315 
316 	if (profile == 0x001A)
317 		dp = &cdr_dvdplusrw;
318 	if ((profile == 0x001B) || (profile == 0x002B))
319 		dp = &cdr_dvdplusr;
320 #ifdef	XX
321 	if (!dvd)			/* SCSI-3/mmc CD drive		*/
322 		return (NULL);
323 #endif
324 
325 	return (dp);
326 }
327 
328 LOCAL int
attach_dvdplus(scgp,dp)329 attach_dvdplus(scgp, dp)
330 	SCSI	*scgp;
331 	cdr_t	*dp;
332 {
333 	Uchar	mode[0x100];
334 	struct	cd_mode_page_2A *mp;
335 	struct	ricoh_mode_page_30 *rp = NULL;
336 	Ulong	xspeed;
337 	Ulong	mp2Aspeed;
338 
339 
340 	allow_atapi(scgp, TRUE); /* Try to switch to 10 byte mode cmds */
341 
342 	scgp->silent++;
343 	mp = mmc_cap(scgp, NULL); /* Get MMC capabilities in allocated mp */
344 	scgp->silent--;
345 	if (mp == NULL)
346 		return (-1);	/* Pre SCSI-3/mmc drive		*/
347 
348 	dp->cdr_cdcap = mp;	/* Store MMC cap pointer	*/
349 
350 	/*
351 	 * XXX hier sollte drive max write speed & drive cur write speed
352 	 * XXX gesetzt werden.
353 	 */
354 	dp->cdr_dstat->ds_dr_max_rspeed = a_to_u_2_byte(mp->max_read_speed)/1385;
355 	if (dp->cdr_dstat->ds_dr_max_rspeed == 0)
356 		dp->cdr_dstat->ds_dr_max_rspeed = 47;
357 	dp->cdr_dstat->ds_dr_cur_rspeed = a_to_u_2_byte(mp->cur_read_speed)/1385;
358 	if (dp->cdr_dstat->ds_dr_cur_rspeed == 0)
359 		dp->cdr_dstat->ds_dr_cur_rspeed = 47;
360 
361 	dp->cdr_dstat->ds_dr_max_wspeed = a_to_u_2_byte(mp->max_write_speed)/1385;
362 	if (mp->p_len >= 28)
363 		dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->v3_cur_write_speed)/1385;
364 	else
365 		dp->cdr_dstat->ds_dr_cur_wspeed = a_to_u_2_byte(mp->cur_write_speed)/1385;
366 
367 	/*
368 	 * NEC drives incorrectly return CD speed values in mode page 2A.
369 	 * Try MMC3 get performance in hope that values closer to DVD speeds
370 	 * are always more correct than what is found in mode page 2A.
371 	 */
372 	xspeed = 0;
373 	scsi_get_perf_maxspeed(scgp, NULL, &xspeed, NULL);
374 
375 	mp2Aspeed = a_to_u_2_byte(mp->max_write_speed);
376 
377 	if (lverbose > 2) {
378 		printf(_("max page 2A speed %lu (%lux), max perf speed %lu (%lux)\n"),
379 			mp2Aspeed, mp2Aspeed/1385,
380 			xspeed, xspeed/1385);
381 	}
382 
383 	if ((is_cdspeed(mp2Aspeed) && !is_cdspeed(xspeed)) ||
384 	    (mp2Aspeed < 10000 && xspeed > 10000)) {
385 		dp->cdr_dstat->ds_dr_max_wspeed = xspeed/1385;
386 		xspeed = 0;
387 		scsi_get_perf_curspeed(scgp, NULL, &xspeed, NULL);
388 		if (xspeed > 0)
389 			dp->cdr_dstat->ds_dr_cur_wspeed = xspeed / 1385;
390 	}
391 
392 	if (dp->cdr_speedmax > dp->cdr_dstat->ds_dr_max_wspeed)
393 		dp->cdr_speedmax = dp->cdr_dstat->ds_dr_max_wspeed;
394 
395 	if (dp->cdr_speeddef > dp->cdr_speedmax)
396 		dp->cdr_speeddef = dp->cdr_speedmax;
397 
398 	rp = get_justlink_ricoh(scgp, mode);
399 
400 	if (mp->p_len >= 28)
401 		dp->cdr_flags |= CDR_MMC3;
402 	if (get_curprofile(scgp) >= 0)
403 		dp->cdr_flags |= CDR_MMC3;
404 	if (mp->p_len >= 24)
405 		dp->cdr_flags |= CDR_MMC2;
406 	dp->cdr_flags |= CDR_MMC;
407 
408 	if (mp->loading_type == LT_TRAY)
409 		dp->cdr_flags |= CDR_TRAYLOAD;
410 	else if (mp->loading_type == LT_CADDY)
411 		dp->cdr_flags |= CDR_CADDYLOAD;
412 
413 	if (mp->BUF != 0)
414 		dp->cdr_flags |= CDR_BURNFREE;
415 
416 	check_writemodes_mmc(scgp, dp);
417 	/*
418 	 * To avoid that silly people try to call cdrecord will write modes
419 	 * that are illegal for DVDs, we clear anything that does now work.
420 	 */
421 	dp->cdr_flags &= ~(CDR_RAW|CDR_RAW16|CDR_RAW96P|CDR_RAW96R|CDR_SRAW96P|CDR_SRAW96R);
422 	dp->cdr_flags &= ~(CDR_TAO);
423 
424 	if (scgp->inq != NULL) {
425 		if (strbeg("PIONEER", scgp->inq->inq_vendor_info)) {
426 			if (strbeg("DVD-RW  DVR-103", scgp->inq->inq_prod_ident) ||
427 			    strbeg("DVD-R DVD-R7322", scgp->inq->inq_prod_ident)) {
428 				mp->BUF = 1;
429 			}
430 		}
431 	}
432 	if (mp->BUF != 0) {
433 		dp->cdr_flags |= CDR_BURNFREE;
434 	} else if (rp) {
435 		if ((dp->cdr_cmdflags & F_DUMMY) && rp->TWBFS && rp->BUEFS)
436 			dp->cdr_flags |= CDR_BURNFREE;
437 
438 		if (rp->BUEFS)
439 			dp->cdr_flags |= CDR_BURNFREE;
440 	}
441 
442 	if (rp && rp->AWSCS)
443 		dp->cdr_flags |= CDR_FORCESPEED;
444 
445 
446 	if ((dp->cdr_flags & (CDR_SAO)) != (CDR_SAO)) {
447 		/*
448 		 * XXX Ist dies ueberhaupt noch notwendig seit wir nicht
449 		 * XXX mehr CDR_TAO vorgaukeln muessen?
450 		 *
451 		 * Das Panasonic DVD-R mag check_writemodes_mmc() nicht
452 		 * hilft das vielleicht?
453 		 */
454 		dp->cdr_flags |= CDR_SAO;
455 	}
456 
457 	if (driveropts != NULL) {
458 		char	*p;
459 
460 		if (strcmp(driveropts, "help") == 0) {
461 			mmc_opthelp(scgp, dp, 0);
462 		}
463 
464 		p = hasdrvopt(driveropts, "burnfree");
465 		if (p == NULL)
466 			p = hasdrvopt(driveropts, "burnproof");
467 		if (p != NULL && (dp->cdr_flags & CDR_BURNFREE) != 0) {
468 			if (*p == '1') {
469 				dp->cdr_dstat->ds_cdrflags |= RF_BURNFREE;
470 			} else if (*p == '0') {
471 				dp->cdr_dstat->ds_cdrflags &= ~RF_BURNFREE;
472 			}
473 		}
474 
475 		p = hasdrvopt(driveropts, "forcespeed");
476 		if (p != NULL && *p == '1' && (dp->cdr_flags & CDR_FORCESPEED) != 0) {
477 			dp->cdr_dstat->ds_cdrflags |= RF_FORCESPEED;
478 		}
479 
480 		p = hasdrvoptx(driveropts, "layerbreak", 0);
481 		if (p != NULL) {
482 			char	*ep;
483 			Llong	ll;
484 			Int32_t	lb;
485 
486 			ep = astoll(p, &ll);
487 			lb = ll;
488 			if ((*ep != '\0' && *ep != ',') || *p == '\0' ||
489 			    ll <= 0 || ll != lb) {
490 				errmsgno(EX_BAD,
491 					_("Bad layer break value '%s'.\n"), p);
492 				return (-1);
493 			}
494 			dp->cdr_dstat->ds_layer_break = lb;
495 		}
496 		if (dp->cdr_dstat->ds_layer_break >= 0 &&
497 		    get_curprofile(scgp) != 0x2B) {
498 			errmsgno(EX_BAD,
499 			_("Cannot set layer break on this drive/medium.\n"));
500 			return (-1);
501 		}
502 		if (dp->cdr_dstat->ds_layer_break != -1 &&
503 		    dp->cdr_dstat->ds_layer_break !=
504 		    roundup(dp->cdr_dstat->ds_layer_break, 16)) {
505 			errmsgno(EX_BAD,
506 			_("Layer break at %d is not properly aligned.\n"),
507 				dp->cdr_dstat->ds_layer_break);
508 			return (-1);
509 		}
510 	}
511 
512 	/*
513 	 * Raise the default timeout.
514 	 * The first write takes a long time as it writes the lead in.
515 	 */
516 	if (scgp->deftimeout < 100)
517 		scg_settimeout(scgp, 100);	/* 1:40			*/
518 
519 
520 	return (0);
521 }
522 
523 LOCAL void
di_to_dstat(dip,dsp)524 di_to_dstat(dip, dsp)
525 	struct disk_info	*dip;
526 	dstat_t	*dsp;
527 {
528 	dsp->ds_diskid = a_to_u_4_byte(dip->disk_id);
529 
530 	dsp->ds_flags |= DSF_NOCD|DSF_DVD;	/* This is a DVD */
531 
532 	if (dip->did_v)
533 		dsp->ds_flags |= DSF_DID_V;
534 	dsp->ds_disktype = dip->disk_type;
535 	dsp->ds_diskstat = dip->disk_status;
536 	dsp->ds_sessstat = dip->sess_status;
537 	if (dip->erasable)
538 		dsp->ds_flags |= DSF_ERA;
539 
540 	dsp->ds_trfirst	   = dip->first_track;
541 	dsp->ds_trlast	   = dip->last_track_ls;
542 	dsp->ds_trfirst_ls = dip->first_track_ls;
543 
544 #ifdef	nono
545 	/*
546 	 * On DVD systems, there is no lead out start time
547 	 * in the disk info because there is no time based data.
548 	 */
549 	dsp->ds_maxblocks = msf_to_lba(dip->last_lead_out[1],
550 					dip->last_lead_out[2],
551 					dip->last_lead_out[3], TRUE);
552 #endif
553 }
554 
555 LOCAL int
init_dvdplus(scgp,dp)556 init_dvdplus(scgp, dp)
557 	SCSI	*scgp;
558 	cdr_t	*dp;
559 {
560 	return (speed_select_dvdplus(scgp, dp, NULL));
561 }
562 
563 LOCAL int
getdisktype_dvdplus(scgp,dp)564 getdisktype_dvdplus(scgp, dp)
565 	SCSI	*scgp;
566 	cdr_t	*dp;
567 {
568 extern	char	*buf;
569 	dstat_t	*dsp = dp->cdr_dstat;
570 	struct disk_info *dip;
571 	Uchar	mode[0x100];
572 	struct rzone_info *rp;
573 	struct dvd_structure_00 *sp;
574 	int	len;
575 	BOOL	did_dummy = FALSE;
576 	BOOL	did_reload = FALSE;
577 	int	profile;
578 	Int32_t	maxblocks;
579 	Ulong	end_lba;
580 
581 /*	if (lverbose > 0)*/
582 /*		print_laserlog(scgp);*/
583 
584 /*	if (lverbose > 2)*/
585 /*		print_logpages(scgp);*/
586 
587 
588 	if (dsp->ds_type == DST_UNKNOWN) {
589 		profile = get_curprofile(scgp);
590 		if (profile >= 0)
591 			dsp->ds_type = profile;
592 	}
593 
594 	if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0) {
595 		if (((dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == 0) ||
596 				lverbose > 1) {
597 			extern	void print_dvd_info __PR((SCSI *_scgp));
598 
599 			/*
600 			 * Das DVD Medieninfo ist so lang, da� wir es
601 			 * beim Schreiben mit -v noch nicht ausgeben.
602 			 */
603 			print_dvd_info(scgp);
604 		}
605 	}
606 
607 again:
608 	dip = (struct disk_info *)buf;
609 	if (get_diskinfo(scgp, dip, sizeof (*dip)) < 0)
610 		return (-1);
611 
612 	/*
613 	 * Check for non writable disk first.
614 	 */
615 #ifdef	DVDPLUS_DEBUG
616 error("DISK STATUS %X\n", dip->disk_status);
617 #endif
618 	if (dip->disk_status == DS_COMPLETE &&
619 			(dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == RF_WRITE) {
620 
621 		profile = get_curprofile(scgp);
622 		if (profile == 0x001A) {	/* This is a DVD+RW */
623 			if (dp->cdr_cmdflags & F_FIX)
624 				return (0);
625 		}
626 
627 
628 		if (!did_dummy) {
629 			int	xspeed = 0xFFFF;
630 			int	oflags = dp->cdr_cmdflags;
631 
632 			/*
633 			 * Try to clear the dummy bit to reset the virtual
634 			 * drive status. Not all drives support it even though
635 			 * it is mentioned in the MMC standard.
636 			 */
637 			if (lverbose)
638 				printf(_("Trying to clear drive status.\n"));
639 
640 			dp->cdr_cmdflags &= ~F_DUMMY;
641 			speed_select_dvdplus(scgp, dp, &xspeed);
642 			dp->cdr_cmdflags = oflags;
643 			scgp->silent++;
644 			rezero_unit(scgp);
645 			scgp->silent--;
646 			did_dummy = TRUE;
647 			goto again;
648 		}
649 		if (!did_reload && profile == 0x001A) {	/* This is a DVD+RW */
650 			scgp->silent++;
651 			len = read_scsi(scgp, buf, 0, 1);
652 			scgp->silent--;
653 			if (len < 0) {
654 				/*
655 				 * DVD+RW "complete" but unreadable
656 				 * Trying to clear drive status did not work...
657 				 * This happens if the DVD+RW media was erased
658 				 * by the Ricoh Vendor Unique command
659 				 */
660 				reload_media(scgp, dp);
661 				did_reload = TRUE;
662 				goto again;
663 			}
664 		}
665 		/*
666 		 * Trying to clear drive status did not work...
667 		 * XXX This most likely makes no sense with DVD+R
668 		 */
669 /*		reload_media(scgp, dp);*/
670 	}
671 	if (get_diskinfo(scgp, dip, sizeof (*dip)) < 0)
672 		return (-1);
673 	di_to_dstat(dip, dsp);
674 
675 #ifdef	DVDPLUS_DEBUG
676 error("dtype %d era %d sess stat %d disk stat %d\n",
677 dip->dtype,
678 dip->erasable,
679 dip->sess_status,
680 dip->disk_status);
681 error("Dirty %d Format status %d\n", dip->dbit, dip->bg_format_stat);
682 error("disk type %X\n",
683 dip->disk_type);
684 {
685 	long nwa = -1;
686 
687 	next_wr_addr_dvdplusr(scgp, (track_t *)NULL, &nwa);
688 	error("NWA: %ld\n", nwa);
689 }
690 #endif
691 
692 
693 	profile = get_curprofile(scgp);
694 	if (profile == 0x001A) {
695 		dsp->ds_flags |= DSF_DVD_PLUS_RW;	/* This is a DVD+RW */
696 		if (dip->disk_status == DS_EMPTY) {	/* Unformatted	    */
697 			if (dip->disk_type != SES_UNDEF) {	/* Not a CD */
698 				printf(_("WARNING: Drive returns illegal Disk type %s.\n"),
699 							get_ses_type(dip->disk_type));
700 			}
701 			dsp->ds_flags |= DSF_NEED_FORMAT;
702 			if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0)
703 				print_format_capacities(scgp);
704 			return (0);
705 		}
706 	} else if (profile == 0x001B) {
707 		dsp->ds_flags |= DSF_DVD_PLUS_R;	/* This is a DVD+R */
708 	}
709 #ifdef	DVDPLUS_DEBUG
710 error("profile %X dsp->ds_flags 0x%X\n", profile, dsp->ds_flags);
711 #endif
712 
713 	/*
714 	 * This information is based on a logical recording zone
715 	 * and may not always be correct.
716 	 * XXX Check this if we want to support anything else but
717 	 * XXX one data track on DAO mode. The current firmware
718 	 * XXX of the recorder supports only this method but future
719 	 * XXX releases may support more.
720 	 */
721 	fillbytes((caddr_t)mode, sizeof (mode), '\0');
722 	rp = (struct rzone_info *)mode;
723 	read_rzone_info(scgp, (caddr_t)rp, sizeof (struct rzone_info));
724 
725 	if ((dp->cdr_dstat->ds_cdrflags & RF_PRATIP) != 0) {
726 		if (((dsp->ds_cdrflags & (RF_WRITE|RF_BLANK)) == 0) ||
727 				lverbose > 1) {
728 			przone(rp);
729 			print_format_capacities(scgp);
730 		}
731 	}
732 #define	needed_for_pioneer_a06
733 #ifdef	needed_for_pioneer_a06
734 	/*
735 	 * Old code used with the S101 seems to be needed for DVD+RW
736 	 * and the Pioneer A06 if the medium is not yet fully formatted.
737 	 */
738 	dsp->ds_maxblocks = a_to_u_4_byte(rp->rzone_size);
739 #ifdef	DVDPLUS_DEBUG
740 error("MAXBLO %d from rzone size\n", dsp->ds_maxblocks);
741 #endif
742 	if (dsp->ds_maxblocks == 0)
743 #endif
744 	dsp->ds_maxblocks = a_to_u_4_byte(rp->free_blocks);
745 #ifdef	DVDPLUS_DEBUG
746 error("MAXBLO %d\n", dsp->ds_maxblocks);
747 error("MAXBLO %d from free_blocks\n", (int)a_to_u_4_byte(rp->free_blocks));
748 #endif
749 	if (rp->nwa_v)
750 		dsp->ds_maxblocks += a_to_u_4_byte(rp->next_recordable_addr);
751 #ifdef	DVDPLUS_DEBUG
752 error("NWAv %d Next rec addr %d\n", rp->nwa_v, (int)a_to_u_4_byte(rp->next_recordable_addr));
753 #endif
754 	maxblocks = dsp->ds_maxblocks;
755 
756 	/*
757 	 * XXX this was: if (dip->disk_status == DS_EMPTY)
758 	 * The '_NEC    ' 'DVD_RW ND-3500AG' may return written DVD+RW with
759 	 * status DS_COMPLETE although they may be overwritten.
760 	 */
761 	if (dip->disk_status == DS_COMPLETE && profile != 0x001A)
762 		return (drive_getdisktype(scgp, dp));
763 
764 	/*
765 	 * This information is based on the physical pre recorded information.
766 	 * First try to find the len supported by the actual drive.
767 	 */
768 	fillbytes((caddr_t)mode, sizeof (mode), '\0');
769 	scgp->silent++;
770 	if (read_dvd_structure(scgp, (caddr_t)mode, 2, 0, 0, 0, 0) < 0) {
771 		scgp->silent--;
772 		if (lverbose > 2)
773 			errmsgno(EX_BAD, _("Cannot read DVD structure 00.\n"));
774 		return (drive_getdisktype(scgp, dp));
775 	}
776 	scgp->silent--;
777 	len = a_to_u_2_byte(mode);
778 	len += 2;			/* Data len is not included */
779 
780 	if (len > sizeof (struct dvd_structure_00)) {
781 		len = sizeof (struct dvd_structure_00);
782 		/*
783 		 * The ACARD TECH AEC-7720 ATAPI<->SCSI adaptor
784 		 * chokes if we try to transfer odd byte counts (rounds up to
785 		 * even byte counts and thus causes a DMA overflow and a
786 		 * bus reset), so make the byte count even.
787 		 */
788 		len += 1;
789 		len &= ~1;
790 	}
791 	fillbytes((caddr_t)mode, sizeof (mode), '\0');
792 	sp = (struct dvd_structure_00 *)mode;
793 	if (read_dvd_structure(scgp, (caddr_t)sp, len, 0, 0, 0, 0) < 0)
794 		return (drive_getdisktype(scgp, dp));
795 
796 /*	if (lverbose > 1)*/
797 /*		print_dvd00(sp);*/
798 	/*
799 	 * Bei Pioneer ist Phys End ist nur bei dem S101 != 0.
800 	 * Bei Panasonic ist Phys End == Phys Start.
801 	 */
802 	if ((profile != 0x001A) &&
803 	    (dp->cdr_cmdflags & F_MSINFO) == 0 &&
804 	    (a_to_u_3_byte(sp->phys_end) != 0) &&
805 			(dsp->ds_maxblocks !=
806 			(long)(a_to_u_3_byte(sp->phys_end) - a_to_u_3_byte(sp->phys_start) + 1))) {
807 #ifdef	__nonono__
808 		printf("WARNING: Phys disk size %ld differs from rzone size %ld! Prerecorded disk?\n",
809 			(long)(a_to_u_3_byte(sp->phys_end) - a_to_u_3_byte(sp->phys_start) + 1),
810 			(long)dsp->ds_maxblocks);
811 		printf("WARNING: Phys start: %ld Phys end %ld\n",
812 			(long)a_to_u_3_byte(sp->phys_start),
813 			(long)a_to_u_3_byte(sp->phys_end));
814 #endif
815 		/*
816 		 * Workaround for some drive media combinations.
817 		 * At least the drive	'HL-DT-ST' 'DVD-RAM GH22NP20' '1.02'
818 		 * does not report maxblocks correctly with 'CMC MAG' 'M01'
819 		 * DVD+R media.
820 		 * Use the information from ADIP instead.
821 		 */
822 #ifdef	DVDPLUS_DEBUG
823 error("MAXBLOx1 %d\n", dsp->ds_maxblocks);
824 #endif
825 		if ((long)dsp->ds_maxblocks == 0) {
826 			printf(_("WARNING: Drive returns zero media size. Using media size from ADIP.\n"));
827 			dsp->ds_maxblocks = a_to_u_3_byte(sp->phys_end) - a_to_u_3_byte(sp->phys_start) + 1;
828 		}
829 	}
830 #ifdef	DVDPLUS_DEBUG
831 error("MAXBLOx %d\n", dsp->ds_maxblocks);
832 error("phys start %d phys end %d\n", a_to_u_3_byte(sp->phys_start), a_to_u_3_byte(sp->phys_end));
833 error("MAXBLO %d from phys end - phys start\n", (int)(a_to_u_3_byte(sp->phys_end) - a_to_u_3_byte(sp->phys_start) + 1));
834 #endif
835 
836 	end_lba = 0L;
837 	scsi_get_perf_maxspeed(scgp, (Ulong *)NULL, (Ulong *)NULL, &end_lba);
838 #ifdef	DVDPLUS_DEBUG
839 error("end_lba: %lu\n", end_lba);
840 #endif
841 	/*
842 	 * XXX Note that end_lba is unsigned and dsp->ds_maxblocks is signed.
843 	 */
844 	if ((Int32_t)end_lba > dsp->ds_maxblocks) {
845 		if (maxblocks == 0)
846 			printf(_("WARNING: Drive returns zero media size, correcting.\n"));
847 		dsp->ds_maxblocks = end_lba + 1;
848 	}
849 
850 	return (drive_getdisktype(scgp, dp));
851 }
852 
853 LOCAL int
prdiskstatus_dvdplus(scgp,dp)854 prdiskstatus_dvdplus(scgp, dp)
855 	SCSI	*scgp;
856 	cdr_t	*dp;
857 {
858 	return (prdiskstatus(scgp, dp, FALSE));
859 }
860 
861 
862 LOCAL int
speed_select_dvdplus(scgp,dp,speedp)863 speed_select_dvdplus(scgp, dp, speedp)
864 	SCSI	*scgp;
865 	cdr_t	*dp;
866 	int	*speedp;
867 {
868 	Uchar	mode[0x100];
869 	Uchar	moder[0x100];
870 	int	len;
871 	struct	cd_mode_page_05 *mp;
872 	struct	ricoh_mode_page_30 *rp = NULL;
873 	int	val;
874 	Ulong	ul;
875 	BOOL	forcespeed = FALSE;
876 	BOOL	dummy = (dp->cdr_cmdflags & F_DUMMY) != 0;
877 	int	curspeed = 1;
878 
879 	if (speedp)
880 		curspeed = *speedp;
881 
882 	fillbytes((caddr_t)mode, sizeof (mode), '\0');
883 
884 	if (!get_mode_params(scgp, 0x05, _("CD write parameter"),
885 			mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
886 		return (-1);
887 	if (len == 0)
888 		return (-1);
889 
890 	mp = (struct cd_mode_page_05 *)
891 		(mode + sizeof (struct scsi_mode_header) +
892 		((struct scsi_mode_header *)mode)->blockdesc_len);
893 #ifdef	DEBUG
894 	if (lverbose > 1)
895 		scg_prbytes("CD write parameter:", (Uchar *)mode, len);
896 #endif
897 
898 
899 	if (dummy != 0) {
900 		errmsgno(EX_BAD, _("DVD+R/DVD+RW has no -dummy mode.\n"));
901 		return (-1);
902 	}
903 	if (get_curprofile(scgp) == 0x001A) {	/* This is a DVD+RW */
904 		if (dp->cdr_cmdflags & F_FIX)
905 			return (0);
906 	}
907 	mp->test_write = dummy != 0;
908 	/*
909 	 * Set default values:
910 	 * Write type = 02 (disk at once)
911 	 * Track mode = 00 Reserved on Pioneer DVR-S101
912 	 * Data block type = 00 Reserved on Pioneer DVR-S101
913 	 * Session format = 00 Reserved on Pioneer DVR-S101
914 	 * XXX DVR-S101 uses ls_v and link size violating
915 	 * XXX the current MMC2 spec.
916 	 */
917 	mp->write_type = WT_SAO;
918 
919 #ifdef	DEBUG
920 	if (lverbose > 1)
921 		scg_prbytes("CD write parameter:", (Uchar *)mode, len);
922 #endif
923 	if (!set_mode_params(scgp, _("CD write parameter"), mode, len, 0, -1)) {
924 		return (-1);
925 	}
926 
927 	/*
928 	 * Neither set nor get speed.
929 	 */
930 	if (speedp == 0)
931 		return (0);
932 
933 
934 	rp = get_justlink_ricoh(scgp, moder);
935 	if ((dp->cdr_flags & CDR_FORCESPEED) != 0) {
936 		forcespeed = rp && rp->AWSCD != 0;
937 	}
938 
939 	if (lverbose && (dp->cdr_flags & CDR_FORCESPEED) != 0)
940 		printf(_("Forcespeed is %s.\n"), forcespeed?_("ON"):_("OFF"));
941 
942 	if (!forcespeed && (dp->cdr_dstat->ds_cdrflags & RF_FORCESPEED) != 0) {
943 		printf(_("Turning forcespeed on\n"));
944 		forcespeed = TRUE;
945 	}
946 	if (forcespeed && (dp->cdr_dstat->ds_cdrflags & RF_FORCESPEED) == 0) {
947 		printf(_("Turning forcespeed off\n"));
948 		forcespeed = FALSE;
949 	}
950 	if ((dp->cdr_flags & CDR_FORCESPEED) != 0) {
951 
952 		if (rp) {
953 			rp->AWSCD = forcespeed?1:0;
954 			set_mode_params(scgp, _("Ricoh Vendor Page"), moder, moder[0]+1, 0, -1);
955 			rp = get_justlink_ricoh(scgp, moder);
956 		}
957 	}
958 
959 	/*
960 	 * DVD single speed is 1385 kB/s
961 	 * Rounding down is guaranteed.
962 	 */
963 	val = curspeed*1390;
964 	if (val > 0x7FFFFFFF)
965 		val = 0x7FFFFFFF;
966 	if (dp->cdr_flags & CDR_MMC3) {
967 		if (speed_select_mdvd(scgp, -1, val) < 0)
968 			errmsgno(EX_BAD, _("MMC-3 speed select did not work.\n"));
969 	} else {
970 		if (val > 0xFFFF)
971 			val = 0xFFFF;
972 		scgp->silent++;
973 		if (scsi_set_speed(scgp, -1, val, ROTCTL_CLV) < 0) {
974 			/*
975 			 * Don't complain if it does not work,
976 			 * DVD drives may not have speed setting.
977 			 * The DVR-S101 and the DVR-S201 difinitely
978 			 * don't allow to set the speed.
979 			 */
980 		}
981 		scgp->silent--;
982 	}
983 
984 	scgp->silent++;
985 	if (scsi_get_speed(scgp, 0, &val) >= 0) {
986 		if (val > 0) {
987 			curspeed = val / 1385;
988 			*speedp = curspeed;
989 		}
990 	}
991 	/*
992 	 * NEC drives incorrectly return CD speed values in mode page 2A.
993 	 * Try MMC3 get performance in hope that values closer to DVD speeds
994 	 * are always more correct than what is found in mode page 2A.
995 	 */
996 	ul = 0;
997 	if (scsi_get_perf_curspeed(scgp, NULL, &ul, NULL) >= 0) {
998 		if (is_cdspeed(val) && !is_cdspeed(ul)) {
999 			curspeed = ul / 1385;
1000 			*speedp = curspeed;
1001 		}
1002 	}
1003 	scgp->silent--;
1004 	return (0);
1005 }
1006 /*--------------------------------------------------------------------------*/
1007 
1008 LOCAL long	dvd_next_addr;
1009 
1010 LOCAL int
next_wr_addr_dvdplusrw(scgp,trackp,ap)1011 next_wr_addr_dvdplusrw(scgp, trackp, ap)
1012 	SCSI	*scgp;
1013 	track_t	*trackp;
1014 	long	*ap;
1015 {
1016 	if (trackp == 0 || trackp->track <= 1) {
1017 		dvd_next_addr = 0;
1018 	}
1019 	if (ap)
1020 		*ap = dvd_next_addr;
1021 	return (0);
1022 }
1023 
1024 LOCAL int
next_wr_addr_dvdplusr(scgp,trackp,ap)1025 next_wr_addr_dvdplusr(scgp, trackp, ap)
1026 	SCSI	*scgp;
1027 	track_t	*trackp;
1028 	long	*ap;
1029 {
1030 	struct disk_info	di;
1031 	struct rzone_info	rz;
1032 	int			tracks;
1033 	long			next_addr = -1;
1034 
1035 	if (trackp == 0) {
1036 		fillbytes((caddr_t)&di, sizeof (di), '\0');
1037 		if (get_diskinfo(scgp, &di, sizeof (di)) < 0)
1038 			return (-1);
1039 
1040 		tracks = di.last_track_ls + di.last_track_ls_msb * 256;
1041 		fillbytes((caddr_t)&rz, sizeof (rz), '\0');
1042 		if (get_trackinfo(scgp, (caddr_t)&rz, TI_TYPE_TRACK, tracks, sizeof (rz)) < 0)
1043 			return (-1);
1044 		if (!rz.nwa_v)
1045 			return (-1);
1046 		next_addr = a_to_4_byte(rz.next_recordable_addr);
1047 		if (ap)
1048 			*ap = next_addr;
1049 		return (0);
1050 	}
1051 	if (trackp->track <= 1) {
1052 		/*
1053 		 * XXX This is a workaround for the filesize > 2GB problem.
1054 		 * XXX Check this if we support more than one track DAO
1055 		 * XXX or if we give up this hack in favour of real 64bit
1056 		 * XXX filesize support.
1057 		 */
1058 		fillbytes((caddr_t)&rz, sizeof (rz), '\0');
1059 		read_rzone_info(scgp, (caddr_t)&rz, sizeof (struct rzone_info));
1060 		dvd_next_addr = a_to_4_byte(rz.next_recordable_addr);
1061 #ifdef	DVDPLUS_DEBUG
1062 error("NWA: %ld valid: %d\n", dvd_next_addr, rz.nwa_v);
1063 #endif
1064 		if (lverbose > 1)
1065 			printf(_("next writable addr: %ld valid: %d\n"), dvd_next_addr, rz.nwa_v);
1066 	}
1067 	if (ap)
1068 		*ap = dvd_next_addr;
1069 	return (0);
1070 }
1071 
1072 LOCAL int
open_track_dvdplus(scgp,dp,trackp)1073 open_track_dvdplus(scgp, dp, trackp)
1074 	SCSI	*scgp;
1075 	cdr_t	*dp;
1076 	track_t *trackp;
1077 {
1078 	Uchar	mode[0x100];
1079 	int	len;
1080 	long	sectors;
1081 	struct	cd_mode_page_05 *mp;
1082 	int	profile;
1083 
1084 	if (trackp->track > 1)	/* XXX Hack to make one 'track' from several */
1085 		return (0);	/* XXX files in Disk at once mode only.	    */
1086 
1087 	fillbytes((caddr_t)mode, sizeof (mode), '\0');
1088 
1089 	if (!get_mode_params(scgp, 0x05, _("CD write parameter"),
1090 			mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
1091 		return (-1);
1092 	if (len == 0)
1093 		return (-1);
1094 
1095 	mp = (struct cd_mode_page_05 *)
1096 		(mode + sizeof (struct scsi_mode_header) +
1097 		((struct scsi_mode_header *)mode)->blockdesc_len);
1098 
1099 	/*
1100 	 * XXX as long as the Pioneer DVR-S101 only supports a single
1101 	 * XXX data track in DAO mode,
1102 	 * XXX do not set:
1103 	 * XXX track_mode
1104 	 * XXX copy
1105 	 * XXX dbtype
1106 	 *
1107 	 * Track mode = 00 Reserved on Pioneer DVR-S101
1108 	 * Data block type = 00 Reserved on Pioneer DVR-S101
1109 	 * Session format = 00 Reserved on Pioneer DVR-S101
1110 	 * XXX DVR-S101 uses ls_v and link size violating
1111 	 * XXX the current MMC2 spec.
1112 	 */
1113 	/* XXX look into drv_mmc.c for re-integration of above settings */
1114 
1115 #ifdef	DEBUG
1116 	if (lverbose > 1)
1117 		scg_prbytes("CD write parameter:", (Uchar *)mode, len);
1118 #endif
1119 	if (!set_mode_params(scgp, _("CD write parameter"), mode, len, 0, trackp->secsize))
1120 		return (-1);
1121 
1122 	/*
1123 	 * Compile vitual track list
1124 	 */
1125 	sectors = rzone_size(trackp);
1126 #ifdef	__needed_for_dvdplus__
1127 	if (sectors < 0)
1128 		return (-1);
1129 #endif
1130 	profile = get_curprofile(scgp);
1131 	if (profile == 0x2B) {
1132 		if (set_p_layerbreak(scgp, sectors,
1133 				dp->cdr_dstat->ds_layer_break) < 0) {
1134 			return (-1);
1135 		}
1136 	}
1137 #ifdef	__needed_for_dvdplus__
1138 	return (reserve_tr_rzone(scgp, sectors));
1139 #else
1140 	return (0);
1141 #endif
1142 }
1143 
1144 /*
1145  * XXX rzone_size(trackp) mu� aufgerufen werden, daher mu�
1146  * XXX auch f�r DVD+RW eine non-dummy open_track() Funktion da sein.
1147  */
1148 /*
1149  * XXX Hack to make one 'track' from several
1150  * XXX files in Disk at once mode only.
1151  * XXX Calculate track size and reserve rzone.
1152  */
1153 LOCAL long
rzone_size(trackp)1154 rzone_size(trackp)
1155 	track_t *trackp;	/* Called with &track[1] */
1156 {
1157 	int	i;
1158 	BOOL	vtracks = FALSE;
1159 	long	sectors = 0L;
1160 	Llong	ttrsize = 0L;
1161 	Llong	tamount = 0L;
1162 	Llong	amount;
1163 	long	secsize = trackp->secsize;
1164 
1165 	for (i = 0; i < MAX_TRACK; i++) {
1166 		if (is_last(&trackp[i]))
1167 			break;
1168 	}
1169 	if (i >= 1)
1170 		vtracks = TRUE;
1171 	if (vtracks && lverbose)
1172 		printf(_("Compiling virtual track list ...\n"));
1173 
1174 	for (i = 0; i < MAX_TRACK; i++) {
1175 		if (trackp[i].tracksize < (tsize_t)0) {
1176 			errmsgno(EX_BAD, _("VTrack %d has unknown length.\n"), i);
1177 			return (-1);
1178 		}
1179 		amount = roundup(trackp[i].tracksize, secsize);
1180 		amount += (Llong)trackp[i].padsecs * secsize;
1181 		sectors += amount/secsize;
1182 		ttrsize += trackp[i].tracksize;
1183 		tamount += amount;
1184 		if (vtracks && lverbose)
1185 			printf(_("Vtrack:  %d size: %lld bytes %lld rounded (%lld sectors)\n"),
1186 				(int)trackp[i].track, (Llong)trackp[i].tracksize,
1187 				amount, amount / (Llong)secsize);
1188 
1189 		if (is_last(&trackp[i]))
1190 			break;
1191 
1192 		/*
1193 		 * XXX Is it possible for a DVD that input sector size
1194 		 * XXX differes from output sector size?
1195 		 * XXX I believe that not.
1196 		 */
1197 		if (trackp[i].tracksize % secsize) {
1198 			comerrno(EX_BAD, _("Virtual track %d is not a multiple of secsize.\n"), (int)trackp[i].track);
1199 		}
1200 	}
1201 
1202 	if (vtracks && lverbose)
1203 		printf(_("Vtracks: %d size: %lld bytes %lld rounded (%ld sectors) total\n"),
1204 			i+1, ttrsize, tamount, sectors);
1205 
1206 	return (sectors);
1207 }
1208 
1209 LOCAL int
close_track_dvdplus(scgp,dp,trackp)1210 close_track_dvdplus(scgp, dp, trackp)
1211 	SCSI	*scgp;
1212 	cdr_t	*dp;
1213 	track_t	*trackp;
1214 {
1215 	long	sectors = 0L;
1216 	Llong	amount;
1217 	long	secsize = trackp->secsize;
1218 
1219 	/*
1220 	 * Compute the start of the next "track" for the hack
1221 	 * that allows to have a track in more than one file.
1222 	 * XXX Check this if the vtrack code is removed.
1223 	 */
1224 	amount = roundup(trackp->tracksize, secsize);
1225 	amount += (Llong)trackp->padsecs * secsize;
1226 	sectors += amount/secsize;
1227 
1228 	dvd_next_addr += sectors;
1229 
1230 	return (0);
1231 }
1232 
1233 #ifdef	__needed_for_dvd_plusr__
1234 LOCAL int
open_session_dvd(scgp,dp,trackp)1235 open_session_dvd(scgp, dp, trackp)
1236 	SCSI	*scgp;
1237 	cdr_t	*dp;
1238 	track_t	*trackp;
1239 {
1240 	Uchar	mode[0x100];
1241 	Uchar	moder[0x100];
1242 	int	len;
1243 	struct	cd_mode_page_05 *mp;
1244 	struct	ricoh_mode_page_30 *rp = NULL;
1245 	BOOL	burnfree = FALSE;
1246 
1247 	fillbytes((caddr_t)mode, sizeof (mode), '\0');
1248 
1249 	if (!get_mode_params(scgp, 0x05, _("CD write parameter"),
1250 			mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len))
1251 		return (-1);
1252 	if (len == 0)
1253 		return (-1);
1254 
1255 	mp = (struct cd_mode_page_05 *)
1256 		(mode + sizeof (struct scsi_mode_header) +
1257 		((struct scsi_mode_header *)mode)->blockdesc_len);
1258 
1259 	/*
1260 	 * XXX as long as the Pioneer DVR-S101 only supports a single
1261 	 * XXX data track in DAO mode,
1262 	 * XXX do not set:
1263 	 * XXX multi_session
1264 	 * XXX sessipon_format
1265 	 *
1266 	 * Track mode = 00 Reserved on Pioneer DVR-S101
1267 	 * Data block type = 00 Reserved on Pioneer DVR-S101
1268 	 * Session format = 00 Reserved on Pioneer DVR-S101
1269 	 * XXX DVR-S101 uses ls_v and link size violating
1270 	 * XXX the current MMC2 spec.
1271 	 */
1272 	/* XXX look into drv_mmc.c for re-integration of above settings */
1273 	mp->write_type = WT_SAO;
1274 
1275 
1276 	rp = get_justlink_ricoh(scgp, moder);
1277 
1278 	if (dp->cdr_cdcap->BUF != 0) {
1279 		burnfree = mp->BUFE != 0;
1280 	} else if ((dp->cdr_flags & CDR_BURNFREE) != 0) {
1281 		burnfree = rp && rp->BUEFE != 0;
1282 	}
1283 
1284 	if (lverbose && (dp->cdr_flags & CDR_BURNFREE) != 0)
1285 		printf(_("BURN-Free is %s.\n"), burnfree?_("ON"):_("OFF"));
1286 
1287 	if (!burnfree && (dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) != 0) {
1288 		printf(_("Turning BURN-Free on\n"));
1289 		burnfree = TRUE;
1290 	}
1291 	if (burnfree && (dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) == 0) {
1292 		printf(_("Turning BURN-Free off\n"));
1293 		burnfree = FALSE;
1294 	}
1295 	if (dp->cdr_cdcap->BUF != 0) {
1296 		mp->BUFE = burnfree?1:0;
1297 	} else if ((dp->cdr_flags & CDR_BURNFREE) != 0) {
1298 
1299 		if (rp)
1300 			rp->BUEFE = burnfree?1:0;
1301 	}
1302 	if (rp) {
1303 		i_to_2_byte(rp->link_counter, 0);
1304 		if (xdebug)
1305 			scg_prbytes(_("Mode Select Data "), moder, moder[0]+1);
1306 
1307 		set_mode_params(scgp, _("Ricoh Vendor Page"), moder, moder[0]+1, 0, -1);
1308 		rp = get_justlink_ricoh(scgp, moder);
1309 	}
1310 
1311 #ifdef	DEBUG
1312 	if (lverbose > 1)
1313 		scg_prbytes("CD write parameter:", (Uchar *)mode, len);
1314 #endif
1315 	if (!set_mode_params(scgp, _("CD write parameter"), mode, len, 0, -1))
1316 		return (-1);
1317 
1318 	return (0);
1319 }
1320 #endif
1321 
1322 /*
1323  * We need to loop here because of a firmware bug in Pioneer DVD writers.
1324  */
1325 LOCAL int
fixate_dvdplusrw(scgp,dp,trackp)1326 fixate_dvdplusrw(scgp, dp, trackp)
1327 	SCSI	*scgp;
1328 	cdr_t	*dp;
1329 	track_t	*trackp;
1330 {
1331 	int	oldtimeout = scgp->deftimeout;
1332 	int	ret = 0;
1333 	int	i;
1334 #define	MAX_TRIES	15
1335 
1336 	/*
1337 	 * XXX Is this timeout needed for DVD+RW too?
1338 	 * XXX It was introduced for DVD-R that writes at least 800 MB
1339 	 */
1340 	if (scgp->deftimeout < 1000)
1341 		scg_settimeout(scgp, 1000);
1342 
1343 /*scgp->verbose++;*/
1344 	scgp->silent++;
1345 	for (i = 0; i <= MAX_TRIES; i++) {
1346 		if (scsi_flush_cache(scgp, TRUE) < 0) {
1347 			if (!scsi_in_progress(scgp) || i >= MAX_TRIES) {
1348 				if (scgp->verbose <= 0) {
1349 					scg_printerr(scgp);
1350 					scg_printresult(scgp);	/* XXX restore key/code in future */
1351 				}
1352 				printf(_("Trouble flushing the cache\n"));
1353 				scgp->silent--;
1354 				scg_settimeout(scgp, oldtimeout);
1355 				return (-1);
1356 			}
1357 			sleep(1);
1358 		} else {
1359 			break;
1360 		}
1361 	}
1362 	scgp->silent--;
1363 	waitformat(scgp, 300);
1364 
1365 	scgp->silent++;
1366 	for (i = 0; i <= MAX_TRIES; i++) {
1367 		if (scsi_close_tr_session(scgp, CL_TYPE_SESSION, 0, TRUE) < 0) {
1368 			if (!scsi_in_progress(scgp) || i >= MAX_TRIES) {
1369 				if (scgp->verbose <= 0) {
1370 					scg_printerr(scgp);
1371 					scg_printresult(scgp);	/* XXX restore key/code in future */
1372 				}
1373 				printf(_("Trouble closing the session\n"));
1374 				break;
1375 			}
1376 			sleep(1);
1377 		} else {
1378 			break;
1379 		}
1380 	}
1381 	scgp->silent--;
1382 	waitformat(scgp, 300);
1383 /*scgp->verbose--;*/
1384 
1385 	scg_settimeout(scgp, oldtimeout);
1386 	return (ret);
1387 #undef	MAX_TRIES
1388 }
1389 
1390 
1391 LOCAL int
fixate_dvdplusr(scgp,dp,trackp)1392 fixate_dvdplusr(scgp, dp, trackp)
1393 	SCSI	*scgp;
1394 	cdr_t	*dp;
1395 	track_t	*trackp;
1396 {
1397 	int	oldtimeout = scgp->deftimeout;
1398 	int	ret = 0;
1399 	int	key = 0;
1400 	int	code = 0;
1401 	int	trackno;
1402 	int	i;
1403 #define	MAX_TRIES	15
1404 
1405 	/*
1406 	 * XXX Is this timeout needed for DVD+R too?
1407 	 * XXX It was introduced for DVD-R that writes at least 800 MB
1408 	 */
1409 	if (scgp->deftimeout < 1000)
1410 		scg_settimeout(scgp, 1000);
1411 
1412 /*scgp->verbose++;*/
1413 	scgp->silent++;
1414 	for (i = 0; i <= MAX_TRIES; i++) {
1415 		if (scsi_flush_cache(scgp, TRUE) < 0) {
1416 			if (!scsi_in_progress(scgp) || i >= MAX_TRIES) {
1417 				if (scgp->verbose <= 0) {
1418 					scg_printerr(scgp);
1419 					scg_printresult(scgp);	/* XXX restore key/code in future */
1420 				}
1421 				printf(_("Trouble flushing the cache\n"));
1422 				scgp->silent--;
1423 				scg_settimeout(scgp, oldtimeout);
1424 				return (-1);
1425 			}
1426 			sleep(1);
1427 		} else {
1428 			break;
1429 		}
1430 	}
1431 	scgp->silent--;
1432 	key = scg_sense_key(scgp);
1433 	code = scg_sense_code(scgp);
1434 	waitformat(scgp, 600);
1435 	/*
1436 	 * With CDs we used to close the invisible track (0xFF) but
1437 	 * with DVDs this may not work anymore if the unit is MMC-3
1438 	 * or above. Use the real track/border number instead.
1439 	 * We always use the "IMMED" flag - is this OK?
1440 	 */
1441 	trackno = trackp->trackno;
1442 	if (trackno <= 0)
1443 		trackno = 1;
1444 	scgp->silent++;
1445 	for (i = 0; i <= MAX_TRIES; i++) {
1446 		if (scsi_close_tr_session(scgp, CL_TYPE_TRACK, trackno, TRUE) < 0) {
1447 			if (!scsi_in_progress(scgp) || i >= MAX_TRIES) {
1448 				if (scgp->verbose <= 0) {
1449 					scg_printerr(scgp);
1450 					scg_printresult(scgp);	/* XXX restore key/code in future */
1451 				}
1452 				printf(_("Trouble closing the track\n"));
1453 				break;
1454 			}
1455 			sleep(1);
1456 		} else {
1457 			break;
1458 		}
1459 	}
1460 	scgp->silent--;
1461 	key = scg_sense_key(scgp);
1462 	code = scg_sense_code(scgp);
1463 	waitformat(scgp, 600);
1464 
1465 	scgp->silent++;
1466 	for (i = 0; i <= MAX_TRIES; i++) {
1467 		if (scsi_close_tr_session(scgp, 0x06, 0, TRUE) < 0) {
1468 			if (!scsi_in_progress(scgp) || i >= MAX_TRIES) {
1469 				if (scgp->verbose <= 0) {
1470 					scg_printerr(scgp);
1471 					scg_printresult(scgp);	/* XXX restore key/code in future */
1472 				}
1473 				printf(_("Trouble closing the last session\n"));
1474 				break;
1475 			}
1476 			sleep(1);
1477 		} else {
1478 			break;
1479 		}
1480 	}
1481 	scgp->silent--;
1482 	key = scg_sense_key(scgp);
1483 	code = scg_sense_code(scgp);
1484 	waitformat(scgp, 600);
1485 /*scgp->verbose--;*/
1486 
1487 	scg_settimeout(scgp, oldtimeout);
1488 	return (ret);
1489 #undef	MAX_TRIES
1490 }
1491 
1492 
1493 /*--------------------------------------------------------------------------*/
1494 
1495 LOCAL BOOL
dvdplus_ricohbased(scgp)1496 dvdplus_ricohbased(scgp)
1497 	SCSI	*scgp;
1498 {
1499 	if (scgp->inq == NULL)
1500 		return (FALSE);
1501 
1502 	if (strncmp(scgp->inq->inq_vendor_info, "RICOH", 5) == 0) {
1503 		if (strbeg("DVD+RW MP5120", scgp->inq->inq_prod_ident) ||
1504 		    strbeg("DVD+RW MP5125", scgp->inq->inq_prod_ident))
1505 			return (TRUE);
1506 	}
1507 	if (strncmp(scgp->inq->inq_vendor_info, "HP", 2) == 0) {
1508 		if (strbeg("DVD Writer 100j", scgp->inq->inq_prod_ident) ||
1509 		    strbeg("DVD Writer 200j", scgp->inq->inq_prod_ident))
1510 			return (TRUE);
1511 	}
1512 	return (FALSE);
1513 }
1514 
1515 LOCAL int
blank_dvdplus(scgp,dp,addr,blanktype)1516 blank_dvdplus(scgp, dp, addr, blanktype)
1517 	SCSI	*scgp;
1518 	cdr_t	*dp;
1519 	long	addr;
1520 	int	blanktype;
1521 {
1522 /*XXX*/extern char *blank_types[];
1523 
1524 	BOOL	cdrr	 = FALSE;	/* Read CD-R	*/
1525 	BOOL	cdwr	 = FALSE;	/* Write CD-R	*/
1526 	BOOL	cdrrw	 = FALSE;	/* Read CD-RW	*/
1527 	BOOL	cdwrw	 = FALSE;	/* Write CD-RW	*/
1528 	BOOL	dvdwr	 = FALSE;	/* DVD writer	*/
1529 	int	profile;
1530 
1531 	int	flags = DC_ERASE;
1532 	int	blanksize = 0x30000;
1533 	int	ret;
1534 
1535 	mmc_check(scgp, &cdrr, &cdwr, &cdrrw, &cdwrw, NULL, &dvdwr);
1536 
1537 	profile = get_curprofile(scgp);
1538 	/*
1539 	 * XXX How to check for DVD drives that support DVD-RW
1540 	 */
1541 /*	if (!dvdwr)*/
1542 /*		return (blank_dummy(scgp, dp, addr, blanktype));*/
1543 
1544 	if (!dvdplus_ricohbased(scgp)) {
1545 		errmsgno(EX_BAD, _("Cannot blank DVD+RW media with non Ricoh based drive.\n"));
1546 		if (profile == 0x1A || profile == 0x2A) {
1547 			ret = blank_simul(scgp, dp, addr, blanktype);
1548 			waitformat(scgp, 600);
1549 			scsi_flush_cache(scgp, TRUE);
1550 			waitformat(scgp, 600);
1551 			return (ret);
1552 		}
1553 		return (-1);
1554 	}
1555 
1556 
1557 	if (blanktype == BLANK_DISC) {
1558 		blanksize = 0x26c090;
1559 	} else {
1560 		blanktype = BLANK_MINIMAL;
1561 		blanksize = 0x30000;
1562 	}
1563 	if (lverbose) {
1564 		printf(_("Blanking %s\n"), blank_types[blanktype & 0x07]);
1565 		flush();
1566 	}
1567 	if (driveropts != NULL) {
1568 		char	*p;
1569 
1570 		p = hasdrvopt(driveropts, "erase");
1571 		if (p == NULL)
1572 			p = hasdrvopt(driveropts, "blank");
1573 		if (p != NULL) {
1574 			if (*p == '1')
1575 				flags |= DC_ERASE;
1576 			else
1577 				flags &= ~DC_ERASE;
1578 		}
1579 		p = hasdrvopt(driveropts, "set");
1580 		if (p != NULL) {
1581 			if (*p == '1')
1582 				flags |= CHANGE_SETTING;
1583 			else
1584 				flags &= ~CHANGE_SETTING;
1585 		}
1586 		p = hasdrvopt(driveropts, "dvdr");
1587 		if (p != NULL) {
1588 			if (*p == '1')
1589 				flags |= DVD_PLUS_R;
1590 			else
1591 				flags &= ~DVD_PLUS_R;
1592 		}
1593 	}
1594 
1595 /*Size Min is 0x30000, Size Max is: 0x26c090 */
1596 #ifdef	DVDPLUS_DEBUG
1597 error("Flags: %d blanksize: %d (0x%X)\n", flags, blanksize, blanksize);
1598 #endif
1599 
1600 	ret = ricoh_dvdsetting(scgp, blanksize, flags, TRUE);
1601 	waitformat(scgp, 2000);
1602 	return (ret);
1603 }
1604 
1605 LOCAL int
format_dvdplus(scgp,dp,fmtflags)1606 format_dvdplus(scgp, dp, fmtflags)
1607 	SCSI	*scgp;
1608 	cdr_t	*dp;
1609 	int	fmtflags;
1610 {
1611 	/*
1612 	 * 1.3 Formatting
1613 	 * --------------
1614 	 *
1615 	 * - For efficiency, please use the Format command only on blank discs
1616 	 *
1617 	 * - The command is:
1618 	 *	- "04 11 00 00 00 00 00 00 00 00 00 00
1619 	 *	    ^^^
1620 	 *	    0x10	Format Data
1621 	 *	    0x01	Format Code == 1
1622 	 *	00 82 00 08 00 23 05 40 98 00 00 01"
1623 	 *	^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
1624 	 *	Format		Format
1625 	 *	header		descriptor
1626 	 *	0x80 FOV
1627 	 *	0x20 IMMED
1628 	 *	len == 0x08
1629 	 */
1630 	char	cap_buf[4096];
1631 	char	fmt_buf[128];
1632 	int	len;
1633 	int	i;
1634 	struct scsi_cap_data		*cp;
1635 	struct scsi_format_cap_desc	*lp;
1636 	struct scsi_format_header	*fhp;
1637 	long	blocks = 0;
1638 	struct timeval starttime;
1639 	struct timeval stoptime;
1640 #ifdef	DVDPLUS_DEBUG
1641 	struct timeval stoptime2;
1642 #endif
1643 
1644 	len = get_format_capacities(scgp, cap_buf, sizeof (cap_buf));
1645 	if (len < 0)
1646 		return (-1);
1647 
1648 #ifdef	DVDPLUS_DEBUG
1649 	error("Cap len: %d\n", len);
1650 	scg_prbytes("Format cap:", (Uchar *)cap_buf, len);
1651 #endif
1652 
1653 	cp = (struct scsi_cap_data *)cap_buf;
1654 	lp = cp->list;
1655 	len -= sizeof (struct scsi_format_cap_header);
1656 	if (lp->desc_type == 2) {
1657 		if ((dp->cdr_cmdflags & F_FORCE) == 0) {
1658 			errmsgno(EX_BAD, _("Medium is already formatted.\n"));
1659 			return (-1);
1660 		}
1661 	}
1662 #ifdef	DVDPLUS_DEBUG
1663 	error("hd len: %d len: %d\n", cp->hd.len, len);
1664 #endif
1665 
1666 	for (i = len; i >= sizeof (struct scsi_format_cap_desc);
1667 			i -= sizeof (struct scsi_format_cap_desc), lp++) {
1668 #ifdef	DVDPLUS_DEBUG
1669 		error("blocks %ld fmt 0x%X desc %d blen: %ld\n",
1670 			(long)a_to_u_4_byte(lp->nblock),
1671 			lp->fmt_type,
1672 			lp->desc_type,
1673 			(long)a_to_u_3_byte(lp->blen));
1674 #endif
1675 		if (lp->fmt_type == FCAP_TYPE_DVDPLUS_FULL)
1676 			blocks = a_to_u_4_byte(lp->nblock);
1677 	}
1678 	if (blocks == 0) {
1679 		errmsgno(EX_BAD, _("DVD+RW Full format capacity not found.\n"));
1680 		return (-1);
1681 	}
1682 
1683 	fhp = (struct scsi_format_header *)fmt_buf;
1684 	lp = (struct scsi_format_cap_desc *)&fmt_buf[4];
1685 	fillbytes((caddr_t)fmt_buf, sizeof (fmt_buf), '\0');
1686 
1687 	fhp->enable = 1;
1688 	fhp->immed = 1;
1689 	i_to_2_byte(fhp->length, 8);
1690 	i_to_4_byte(lp->nblock, blocks);
1691 	lp->fmt_type = FCAP_TYPE_DVDPLUS_FULL;
1692 	i_to_3_byte(lp->blen, 0);
1693 /*	i_to_3_byte(lp->blen, 1);*/
1694 
1695 #ifdef	DVDPLUS_DEBUG
1696 	scg_prbytes("Format desc:", (Uchar *)fmt_buf, 12);
1697 #endif
1698 
1699 	if (lverbose) {
1700 		/*
1701 		 * XXX evt. restart Format ansagen...
1702 		 */
1703 		printf(_("Formatting media\n"));
1704 		flush();
1705 	}
1706 	starttime.tv_sec = 0;
1707 	starttime.tv_usec = 0;
1708 	stoptime = starttime;
1709 	gettimeofday(&starttime, (struct timezone *)0);
1710 
1711 	if (format_unit(scgp, fhp, /*fhp->length*/ 8 + sizeof (struct scsi_format_header),
1712 				1, 0, 0, 0, 3800) < 0) {
1713 		return (-1);
1714 	}
1715 
1716 
1717 #ifdef	DVDPLUS_DEBUG
1718 /*	if (ret >= 0 && lverbose) {*/
1719 	if (1) {
1720 		gettimeofday(&stoptime, (struct timezone *)0);
1721 		prtimediff("Format time: ", &starttime, &stoptime);
1722 	}
1723 #endif
1724 	waitformat(scgp, 300);
1725 
1726 #ifdef	DVDPLUS_DEBUG
1727 	gettimeofday(&stoptime2, (struct timezone *)0);
1728 	prtimediff("Format WAIT time: ", &stoptime, &stoptime2);
1729 	prtimediff("Format time TOTAL: ", &starttime, &stoptime2);
1730 #endif
1731 
1732 
1733 #ifdef	DVDPLUS_DEBUG
1734 error("------------> STOP DE-ICE\n");
1735 #endif
1736 	scsi_close_tr_session(scgp, CL_TYPE_STOP_DEICE, 0, TRUE);
1737 	waitformat(scgp, 300);
1738 
1739 #ifdef	DVDPLUS_DEBUG
1740 	gettimeofday(&stoptime2, (struct timezone *)0);
1741 	prtimediff("Format time TOTAL 2 : ", &starttime, &stoptime2);
1742 #endif
1743 
1744 #ifdef	DVDPLUS_DEBUG
1745 error("------------> CLOSE SESSION\n");
1746 #endif
1747 	scsi_close_tr_session(scgp, CL_TYPE_SESSION, 0, TRUE);
1748 	waitformat(scgp, 300);
1749 
1750 #ifdef	DVDPLUS_DEBUG
1751 	gettimeofday(&stoptime2, (struct timezone *)0);
1752 	prtimediff("Format time TOTAL 3: ", &starttime, &stoptime2);
1753 #endif
1754 	return (0);
1755 }
1756 
1757 LOCAL int
waitformat(scgp,secs)1758 waitformat(scgp, secs)
1759 	SCSI	*scgp;
1760 	int	secs;
1761 {
1762 	Uchar   sensebuf[CCS_SENSE_LEN];
1763 	int	printed = 0;
1764 	int	i;
1765 	int	key;
1766 #define	W_SLEEP	2
1767 
1768 	scgp->silent++;
1769 	for (i = 0; i < secs/W_SLEEP; i++) {
1770 		if (test_unit_ready(scgp) >= 0) {
1771 			scgp->silent--;
1772 			return (0);
1773 		}
1774 		key = scg_sense_key(scgp);
1775 		if (key != SC_UNIT_ATTENTION && key != SC_NOT_READY)
1776 			break;
1777 request_sense_b(scgp, (caddr_t)sensebuf, sizeof (sensebuf));
1778 #ifdef	XXX
1779 scg_prbytes("Sense:", sensebuf, sizeof (sensebuf));
1780 scgp->scmd->u_scb.cmd_scb[0] = 2;
1781 movebytes(sensebuf, scgp->scmd->u_sense.cmd_sense, sizeof (sensebuf));
1782 scgp->scmd->sense_count = sizeof (sensebuf);
1783 scg_printerr(scgp);
1784 #endif
1785 /*
1786  * status: 0x2 (CHECK CONDITION)
1787  * Sense Bytes: F0 00 00 00 24 1C 10 0C 00 00 00 00 04 04 00 80 03 F6
1788  * Sense Key: 0x0 No Additional Sense, Segment 0
1789  * Sense Code: 0x04 Qual 0x04 (logical unit not ready, format in progress) Fru 0x0
1790  * Sense flags: Blk 2366480 (valid)
1791  * cmd finished after 0.000s timeout 100s
1792  * Das Fehlt:
1793  * operation 1% done
1794  */
1795 
1796 		if (lverbose && (sensebuf[15] & 0x80)) {
1797 			printed++;
1798 			error(_("operation %d%% done\r"),
1799 				(100*(sensebuf[16] << 8 |
1800 					sensebuf[17]))/(unsigned)65536);
1801 		}
1802 		sleep(W_SLEEP);
1803 	}
1804 	scgp->silent--;
1805 	if (printed)
1806 		error("\n");
1807 	return (-1);
1808 #undef	W_SLEEP
1809 }
1810 
1811 LOCAL int
stats_dvdplus(scgp,dp)1812 stats_dvdplus(scgp, dp)
1813 	SCSI	*scgp;
1814 	cdr_t	*dp;
1815 {
1816 	Uchar mode[256];
1817 	struct	ricoh_mode_page_30 *rp;
1818 	UInt32_t count;
1819 
1820 	if ((dp->cdr_dstat->ds_cdrflags & RF_BURNFREE) == 0)
1821 		return (0);
1822 
1823 	rp = get_justlink_ricoh(scgp, mode);
1824 	if (rp) {
1825 		count = a_to_u_2_byte(rp->link_counter);
1826 		if (lverbose) {
1827 			if (count == 0)
1828 				printf(_("BURN-Free was not used.\n"));
1829 			else
1830 				printf(_("BURN-Free was %d times used.\n"),
1831 					(int)count);
1832 		}
1833 	}
1834 	return (0);
1835 }
1836 
1837 #define	FMTDAT	0x10
1838 #define	CMPLST	0x08
1839 
1840 EXPORT int
format_unit(scgp,fmt,length,list_format,dgdl,interlv,pattern,timeout)1841 format_unit(scgp, fmt, length, list_format, dgdl, interlv, pattern, timeout)
1842 	SCSI	*scgp;
1843 	void	*fmt;
1844 	int	length;
1845 	int	list_format;	/* 0 if fmt == 0			*/
1846 	int	dgdl;		/* disable grown defect list		*/
1847 	int	interlv;
1848 	int	pattern;
1849 	int	timeout;
1850 {
1851 	register struct	scg_cmd	*scmd = scgp->scmd;
1852 
1853 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1854 	scmd->addr = (caddr_t)fmt;
1855 	scmd->size = length;
1856 	scmd->flags = SCG_DISRE_ENA;
1857 	scmd->cdb_len = SC_G0_CDBLEN;
1858 	scmd->sense_len = CCS_SENSE_LEN;
1859 	if (timeout < 0)
1860 		timeout = 24*3600;	/* Kein Timeout XXX kann haengen */
1861 	scmd->timeout = timeout;
1862 	scmd->cdb.g0_cdb.cmd = 0x04;	/* Format Unit */
1863 	scmd->cdb.g0_cdb.lun = scg_lun(scgp);
1864 	scmd->cdb.g0_cdb.high_addr = (fmt?FMTDAT:0)|(dgdl?CMPLST:0)|list_format;
1865 	scmd->cdb.g0_cdb.mid_addr = pattern;
1866 	scmd->cdb.g0_cdb.count = interlv;
1867 
1868 #ifdef	DVDPLUS_DEBUG
1869 	scg_prbytes("Format CDB: ", (u_char *)scmd->cdb.cmd_cdb, scmd->cdb_len);
1870 
1871 /*	if (scgp->verbose && fmt)*/
1872 		scg_prbytes("Format Data:", (u_char *)fmt, length);
1873 #endif
1874 
1875 	scgp->cmdname = "format unit";
1876 
1877 	return (scg_cmd(scgp));
1878 }
1879 
1880 LOCAL int
set_p_layerbreak(scgp,tsize,lbreak)1881 set_p_layerbreak(scgp, tsize, lbreak)
1882 	SCSI	*scgp;
1883 	long	tsize;
1884 	Int32_t	lbreak;
1885 {
1886 	struct dvd_structure_20	lb;
1887 	int			ret;
1888 	UInt32_t		dsize;
1889 	UInt32_t		l0_cap;
1890 
1891 	/*
1892 	 * Layer boundary information 0x20
1893 	 */
1894 	fillbytes((caddr_t)&lb, sizeof (lb), '\0');
1895 	ret = read_dvd_structure(scgp, (caddr_t)&lb, sizeof (lb), 0, 0, 0, 0x20);
1896 	if (ret < 0)
1897 		return (ret);
1898 
1899 	if (lb.res47[0] & 0x80) {
1900 		errmsgno(EX_BAD, _("Layer 0 zone capacity already set.\n"));
1901 		return (-1);
1902 	}
1903 
1904 	l0_cap = a_to_u_4_byte(lb.l0_area_cap);
1905 	if (lbreak > 0 && lbreak > l0_cap) {
1906 		errmsgno(EX_BAD, _("Manual layer break %d > %u not allowed.\n"),
1907 							lbreak, l0_cap);
1908 		return (-1);
1909 	}
1910 	dsize = roundup(tsize, 16);
1911 	if (lbreak <= 0 && dsize <= l0_cap) {
1912 		/*
1913 		 * Allow to write DL media with less than single layer size
1914 		 * in case of manual layer break set up.
1915 		 */
1916 		errmsgno(EX_BAD,
1917 			_("Layer 0 size %u is bigger than expected disk size %u.\n"),
1918 			l0_cap, dsize);
1919 		errmsgno(EX_BAD, _("Use single layer medium.\n"));
1920 		return (-1);
1921 	}
1922 	l0_cap = dsize / 2;
1923 	l0_cap = roundup(l0_cap, 16);
1924 	if (lbreak > 0 && lbreak < l0_cap) {
1925 		errmsgno(EX_BAD, _("Manual layer break %d < %u not allowed.\n"),
1926 							lbreak, l0_cap);
1927 		return (-1);
1928 	}
1929 	if (lbreak > 0)
1930 		l0_cap = lbreak;
1931 	i_to_4_byte(lb.l0_area_cap, l0_cap);
1932 
1933 	ret = send_dvd_structure(scgp, (caddr_t)&lb, sizeof (lb), 0x20);
1934 	return (ret);
1935 }
1936 
1937 LOCAL int
ricoh_dvdsetting(scgp,erase_size,flags,immed)1938 ricoh_dvdsetting(scgp, erase_size, flags, immed)
1939 	SCSI	*scgp;
1940 	int	erase_size;
1941 	int	flags;
1942 	int	immed;
1943 {
1944 	register struct	scg_cmd	*scmd = scgp->scmd;
1945 
1946 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1947 	scmd->flags = SCG_DISRE_ENA;
1948 	scmd->cdb_len = SC_G1_CDBLEN;
1949 	scmd->sense_len = CCS_SENSE_LEN;
1950 	scmd->timeout = 3600;
1951 	scmd->cdb.g1_cdb.cmd = 0xEA;
1952 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
1953 	scmd->cdb.cmd_cdb[1] = immed ? 1 : 0;
1954 	scmd->cdb.cmd_cdb[2] = flags;
1955 	i_to_3_byte(&scmd->cdb.cmd_cdb[3], erase_size);
1956 
1957 	scgp->cmdname = "set_dummy_dvdr_setttings";
1958 
1959 	return (scg_cmd(scgp));
1960 }
1961 
1962 #ifdef	__needed__
1963 /*
1964  * 0x21 Emulation write is OFF
1965  * 0x20 Emulation write is ON
1966  * 0xFF Disk is loading
1967  */
1968 LOCAL int
dummy_plextor(scgp,modecode)1969 dummy_plextor(scgp, modecode)
1970 	SCSI	*scgp;
1971 	int	modecode;
1972 {
1973 	register struct	scg_cmd	*scmd = scgp->scmd;
1974 
1975 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1976 	scmd->flags = SCG_DISRE_ENA;
1977 	scmd->cdb_len = SC_G5_CDBLEN;
1978 	scmd->sense_len = CCS_SENSE_LEN;
1979 	scmd->cdb.g5_cdb.cmd = 0xF3;
1980 	scmd->cdb.cmd_cdb[1] = 0x1F;
1981 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
1982 	scmd->cdb.cmd_cdb[2] = 0x16;
1983 	scmd->cdb.cmd_cdb[3] = modecode;
1984 
1985 	scgp->cmdname = "plextor dummy";
1986 
1987 	if (scg_cmd(scgp) < 0)
1988 		return (-1);
1989 	return (0);
1990 }
1991 #endif
1992