1 /* @(#)scsi_mmc.c	1.51 10/12/19 Copyright 2002-2010 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)scsi_mmc.c	1.51 10/12/19 Copyright 2002-2010 J. Schilling";
6 #endif
7 /*
8  *	SCSI command functions for cdrecord
9  *	covering MMC-3 level and above
10  *
11  *	Copyright (c) 2002-2010 J. Schilling
12  */
13 /*
14  * The contents of this file are subject to the terms of the
15  * Common Development and Distribution License, Version 1.0 only
16  * (the "License").  You may not use this file except in compliance
17  * with the License.
18  *
19  * See the file CDDL.Schily.txt in this distribution for details.
20  * A copy of the CDDL is also available via the Internet at
21  * http://www.opensource.org/licenses/cddl1.txt
22  *
23  * When distributing Covered Code, include this CDDL HEADER in each
24  * file and include the License file CDDL.Schily.txt from this distribution.
25  */
26 
27 /*#define	DEBUG*/
28 
29 #include <schily/mconfig.h>
30 
31 #include <schily/stdio.h>
32 #include <schily/standard.h>
33 #include <schily/stdlib.h>
34 #include <schily/unistd.h>
35 #include <schily/fcntl.h>
36 #include <schily/errno.h>
37 #include <schily/string.h>
38 #include <schily/time.h>
39 
40 #include <schily/utypes.h>
41 #include <schily/btorder.h>
42 #include <schily/intcvt.h>
43 #include <schily/schily.h>
44 #include <schily/nlsdefs.h>
45 
46 #include <scg/scgcmd.h>
47 #include <scg/scsidefs.h>
48 #include <scg/scsireg.h>
49 #include <scg/scsitransp.h>
50 
51 #include "scsimmc.h"
52 #include "cdrecord.h"
53 
54 extern	int	xdebug;
55 extern	int	lverbose;
56 
57 LOCAL struct features {
58 	UInt16_t	code;
59 	char		*name;
60 } fl[] = {
61 	{ 0x0000,	"Profile List", },
62 	{ 0x0001,	"Core", },
63 	{ 0x0002,	"Morphing", },
64 	{ 0x0003,	"Removable Medium", },
65 	{ 0x0004,	"Write Protect", },
66 
67 	{ 0x0010,	"Random Readable", },
68 
69 	{ 0x001D,	"Multi Read", },
70 	{ 0x001E,	"CD Read", },
71 	{ 0x001F,	"DVD Read", },
72 
73 	{ 0x0020,	"Random Writable", },
74 	{ 0x0021,	"Incremental Streaming Writable", },
75 	{ 0x0022,	"Sector Erasable", },
76 	{ 0x0023,	"Formattable", },
77 	{ 0x0024,	"Defect Management", },
78 	{ 0x0025,	"Write Once", },
79 	{ 0x0026,	"Restricted Overwrite", },
80 	{ 0x0027,	"CD-RW CAV Write", },
81 	{ 0x0028,	"MRW", },
82 	{ 0x0029,	"Ehanced Defect Reporting", },
83 	{ 0x002A,	"DVD+RW", },
84 	{ 0x002B,	"DVD+R", },
85 	{ 0x002C,	"Rigid Restricted Overwrite", },
86 	{ 0x002D,	"CD Track at Once", },
87 	{ 0x002E,	"CD Mastering", },
88 	{ 0x002F,	"DVD-R/-RW Write", },
89 
90 	{ 0x0030,	"DDCD Read", },
91 	{ 0x0031,	"DDCD-R Write", },
92 	{ 0x0032,	"DDCD-RW Write", },
93 
94 	{ 0x0033,	"Layer Jump Recording", },
95 
96 	{ 0x0037,	"CD-RW Write", },
97 	{ 0x0038,	"BD-R Pseudo-Overwrite (POW)", },
98 
99 	{ 0x003A,	"DVD+RW/DL Read", },
100 	{ 0x003B,	"DVD+R/DL Read", },
101 
102 	{ 0x0040,	"BD Read", },
103 	{ 0x0041,	"BD Write", },
104 	{ 0x0042,	"Time Safe Recording (TSR)", },
105 
106 	{ 0x0050,	"HD-DVD Read", },
107 	{ 0x0051,	"HD-DVD Write", },
108 
109 	{ 0x0080,	"Hybrid Disk Read", },
110 
111 	{ 0x0100,	"Power Management", },
112 	{ 0x0101,	"S.M.A.R.T.", },
113 	{ 0x0102,	"Embedded Changer", },
114 	{ 0x0103,	"CD Audio analog play", },
115 	{ 0x0104,	"Microcode Upgrade", },
116 	{ 0x0105,	"Time-out", },
117 	{ 0x0106,	"DVD-CSS", },
118 	{ 0x0107,	"Real Time Streaming", },
119 	{ 0x0108,	"Logical Unit Serial Number", },
120 	{ 0x0109,	"Media Serial Number", },
121 	{ 0x010A,	"Disk Control Blocks", },
122 	{ 0x010B,	"DVD CPRM", },
123 	{ 0x010C,	"Microcode Information", },
124 	{ 0x010D,	"AACS", },
125 
126 	{ 0x0110,	"VCPS", },
127 };
128 
129 LOCAL struct profiles {
130 	UInt16_t	code;
131 	char		*name;
132 } pl[] = {
133 	{ 0x0000,	"Reserved", },
134 	{ 0x0001,	"Non -removable Disk", },
135 	{ 0x0002,	"Removable Disk", },
136 	{ 0x0003,	"MO Erasable", },
137 	{ 0x0004,	"MO Write Once", },
138 	{ 0x0005,	"AS-MO", },
139 
140 	/* 0x06..0x07 is reserved */
141 
142 	{ 0x0008,	"CD-ROM", },
143 	{ 0x0009,	"CD-R", },
144 	{ 0x000A,	"CD-RW", },
145 
146 	/* 0x0B..0x0F is reserved */
147 
148 	{ 0x0010,	"DVD-ROM", },
149 	{ 0x0011,	"DVD-R sequential recording", },
150 	{ 0x0012,	"DVD-RAM", },
151 	{ 0x0013,	"DVD-RW restricted overwrite", },
152 	{ 0x0014,	"DVD-RW sequential recording", },
153 	{ 0x0015,	"DVD-R/DL sequential recording", },
154 	{ 0x0016,	"DVD-R/DL layer jump recording", },
155 	{ 0x0017,	"DVD-RW/DL", },
156 
157 	/* 0x18..0x19 is reserved */
158 
159 	{ 0x001A,	"DVD+RW", },
160 	{ 0x001B,	"DVD+R", },
161 
162 	{ 0x0020,	"DDCD-ROM", },
163 	{ 0x0021,	"DDCD-R", },
164 	{ 0x0022,	"DDCD-RW", },
165 
166 	{ 0x002A,	"DVD+RW/DL", },
167 	{ 0x002B,	"DVD+R/DL", },
168 
169 	{ 0x0040,	"BD-ROM", },
170 	{ 0x0041,	"BD-R sequential recording", },
171 	{ 0x0042,	"BD-R random recording", },
172 	{ 0x0043,	"BD-RE", },
173 
174 	/* 0x44..0x4F is reserved */
175 
176 	{ 0x0050,	"HD DVD-ROM", },
177 	{ 0x0051,	"HD DVD-R", },
178 	{ 0x0052,	"HD DVD-RAM", },
179 	{ 0x0053,	"HD DVD-RW", },
180 
181 	/* 0x54..0x57 is reserved */
182 
183 	{ 0x0058,	"HD DVD-R/DL", },
184 
185 	{ 0x005A,	"HD DVD-RW/DL", },
186 
187 	{ 0xFFFF,	"No standard Profile", },
188 };
189 
190 
191 EXPORT	int	get_configuration	__PR((SCSI *scgp, caddr_t bp, int cnt, int st_feature, int rt));
192 LOCAL	int	get_conflen		__PR((SCSI *scgp, int st_feature, int rt));
193 EXPORT	int	get_curprofile		__PR((SCSI *scgp));
194 LOCAL	int	get_profiles		__PR((SCSI *scgp, caddr_t bp, int cnt));
195 EXPORT	int	has_profile		__PR((SCSI *scgp, int profile));
196 EXPORT	int	print_profiles		__PR((SCSI *scgp));
197 EXPORT	int	get_proflist		__PR((SCSI *scgp, BOOL *wp, BOOL *cdp, BOOL *dvdp, BOOL *dvdplusp, BOOL *ddcdp));
198 EXPORT	int	get_wproflist		__PR((SCSI *scgp, BOOL *cdp, BOOL *dvdp,
199 							BOOL *dvdplusp, BOOL *ddcdp));
200 EXPORT	int	get_mediatype		__PR((SCSI *scgp));
201 EXPORT	int	get_singlespeed		__PR((int mt));
202 EXPORT	float	get_secsps		__PR((int mt));
203 EXPORT	char	*get_mclassname		__PR((int mt));
204 EXPORT	int	get_blf			__PR((int mt));
205 
206 LOCAL	int	scsi_get_performance	__PR((SCSI *scgp, caddr_t bp, int cnd, int ndesc, int type, int datatype));
207 EXPORT	int	scsi_get_perf_maxspeed	__PR((SCSI *scgp, Ulong *readp, Ulong *writep, Ulong *endp));
208 EXPORT	int	scsi_get_perf_curspeed	__PR((SCSI *scgp, Ulong *readp, Ulong *writep, Ulong *endp));
209 LOCAL	int	scsi_set_streaming	__PR((SCSI *scgp, Ulong *readp, Ulong *writep, Ulong *endp));
210 EXPORT	int	speed_select_mdvd	__PR((SCSI *scgp, int readspeed, int writespeed));
211 LOCAL	char	*fname			__PR((Uint code));
212 LOCAL	char	*pname			__PR((Uint code));
213 LOCAL	BOOL	fname_known		__PR((Uint code));
214 LOCAL	BOOL	pname_known		__PR((Uint code));
215 EXPORT	int	print_features		__PR((SCSI *scgp));
216 EXPORT	void	print_format_capacities	__PR((SCSI *scgp));
217 EXPORT	int	get_format_capacities	__PR((SCSI *scgp, caddr_t bp, int cnt));
218 EXPORT	int	read_format_capacities	__PR((SCSI *scgp, caddr_t bp, int cnt));
219 
220 EXPORT	void	przone			__PR((struct rzone_info *rp));
221 EXPORT	int	get_diskinfo		__PR((SCSI *scgp, struct disk_info *dip, int cnt));
222 EXPORT	char	*get_ses_type		__PR((int ses_type));
223 EXPORT	void	print_diskinfo		__PR((struct disk_info *dip, BOOL is_cd));
224 EXPORT	int	prdiskstatus		__PR((SCSI *scgp, cdr_t *dp, BOOL is_cd));
225 EXPORT	int	sessstatus		__PR((SCSI *scgp, BOOL is_cd, long *offp, long *nwap));
226 EXPORT	void	print_performance_mmc	__PR((SCSI *scgp));
227 
228 
229 /*
230  * Get feature codes
231  */
232 EXPORT int
get_configuration(scgp,bp,cnt,st_feature,rt)233 get_configuration(scgp, bp, cnt, st_feature, rt)
234 	SCSI	*scgp;
235 	caddr_t	bp;
236 	int	cnt;
237 	int	st_feature;
238 	int	rt;
239 {
240 	register struct	scg_cmd	*scmd = scgp->scmd;
241 
242 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
243 	scmd->addr = bp;
244 	scmd->size = cnt;
245 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
246 	scmd->cdb_len = SC_G1_CDBLEN;
247 	scmd->sense_len = CCS_SENSE_LEN;
248 	scmd->cdb.g1_cdb.cmd = 0x46;
249 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
250 	if (rt & 1)
251 		scmd->cdb.g1_cdb.reladr  = 1;
252 	if (rt & 2)
253 		scmd->cdb.g1_cdb.res  = 1;
254 
255 	i_to_2_byte(scmd->cdb.g1_cdb.addr, st_feature);
256 	g1_cdblen(&scmd->cdb.g1_cdb, cnt);
257 
258 	scgp->cmdname = "get_configuration";
259 
260 	return (scg_cmd(scgp));
261 }
262 
263 /*
264  * Retrieve feature code list length
265  */
266 LOCAL int
get_conflen(scgp,st_feature,rt)267 get_conflen(scgp, st_feature, rt)
268 	SCSI	*scgp;
269 	int	st_feature;
270 	int	rt;
271 {
272 	Uchar	cbuf[8];
273 	int	flen;
274 	int	i;
275 
276 	fillbytes(cbuf, sizeof (cbuf), '\0');
277 	scgp->silent++;
278 	i = get_configuration(scgp, (char *)cbuf, sizeof (cbuf), st_feature, rt);
279 	scgp->silent--;
280 	if (i < 0)
281 		return (-1);
282 	i = sizeof (cbuf) - scg_getresid(scgp);
283 	if (i < 4)
284 		return (-1);
285 
286 	flen = a_to_u_4_byte(cbuf);
287 	if (flen < 4)
288 		return (-1);
289 	return (flen);
290 }
291 
292 EXPORT int
get_curprofile(scgp)293 get_curprofile(scgp)
294 	SCSI	*scgp;
295 {
296 	Uchar	cbuf[8];
297 	int	amt;
298 	int	flen;
299 	int	profile;
300 	int	i;
301 
302 	fillbytes(cbuf, sizeof (cbuf), '\0');
303 	scgp->silent++;
304 	i = get_configuration(scgp, (char *)cbuf, sizeof (cbuf), 0, 0);
305 	scgp->silent--;
306 	if (i < 0)
307 		return (-1);
308 
309 	amt = sizeof (cbuf) - scg_getresid(scgp);
310 	if (amt < 8)
311 		return (-1);
312 	flen = a_to_u_4_byte(cbuf);
313 	if (flen < 4)
314 		return (-1);
315 
316 	profile = a_to_u_2_byte(&cbuf[6]);
317 
318 	if (xdebug > 1)
319 		scg_prbytes(_("Features: "), cbuf, amt);
320 
321 	if (xdebug > 0)
322 		printf(_("feature len: %d current profile 0x%04X len %d\n"),
323 				flen, profile, amt);
324 
325 	return (profile);
326 }
327 
328 LOCAL int
get_profiles(scgp,bp,cnt)329 get_profiles(scgp, bp, cnt)
330 	SCSI	*scgp;
331 	caddr_t	bp;
332 	int	cnt;
333 {
334 	int	amt;
335 	int	flen;
336 	int	i;
337 
338 	flen = get_conflen(scgp, 0, 0);
339 	if (flen < 0)
340 		return (-1);
341 	if (cnt < flen)
342 		flen = cnt;
343 
344 	fillbytes(bp, cnt, '\0');
345 	scgp->silent++;
346 	i = get_configuration(scgp, (char *)bp, flen, 0, 0);
347 	scgp->silent--;
348 	if (i < 0)
349 		return (-1);
350 	amt = flen - scg_getresid(scgp);
351 
352 	flen = a_to_u_4_byte(bp);
353 	if ((flen+4) < amt)
354 		amt = flen+4;
355 
356 	return (amt);
357 }
358 
359 EXPORT int
has_profile(scgp,profile)360 has_profile(scgp, profile)
361 	SCSI	*scgp;
362 	int	profile;
363 {
364 	Uchar	cbuf[1024];
365 	Uchar	*p;
366 	int	flen;
367 	int	prf;
368 	int	i;
369 	int	n;
370 
371 	flen = get_profiles(scgp, (caddr_t)cbuf, sizeof (cbuf));
372 	if (flen < 0)
373 		return (-1);
374 
375 	p = cbuf;
376 	p += 8;		/* Skip feature header	*/
377 	n = p[3];	/* Additional length	*/
378 	n /= 4;
379 	p += 4;
380 
381 	for (i = 0; i < n; i++) {
382 		prf = a_to_u_2_byte(p);
383 		if (xdebug > 0)
384 			printf(_("Profile: 0x%04X "), prf);
385 		if (profile == prf)
386 			return (1);
387 		p += 4;
388 	}
389 	return (0);
390 }
391 
392 EXPORT int
print_profiles(scgp)393 print_profiles(scgp)
394 	SCSI	*scgp;
395 {
396 	Uchar	cbuf[1024];
397 	Uchar	*p;
398 	int	flen;
399 	int	curprofile;
400 	int	profile;
401 	int	i;
402 	int	n;
403 
404 	flen = get_profiles(scgp, (caddr_t)cbuf, sizeof (cbuf));
405 	if (flen < 0)
406 		return (-1);
407 
408 	p = cbuf;
409 	if (xdebug > 1)
410 		scg_prbytes(_("Features: "), cbuf, flen);
411 
412 	curprofile = a_to_u_2_byte(&p[6]);
413 	if (xdebug > 0)
414 		printf(_("feature len: %d current profile 0x%04X\n"),
415 				flen, curprofile);
416 
417 	if (pname_known(curprofile))
418 		printf(_("Current: %s\n"), curprofile == 0 ? _("none") : pname(curprofile));
419 	else
420 		printf(_("Current: 0x%04X unknown\n"), curprofile);
421 
422 	p += 8;		/* Skip feature header	*/
423 	n = p[3];	/* Additional length	*/
424 	n /= 4;
425 	p += 4;
426 
427 	for (i = 0; i < n; i++) {
428 		profile = a_to_u_2_byte(p);
429 		if (xdebug > 0)
430 			printf(_("Profile: 0x%04X "), profile);
431 		else
432 			printf(_("Profile: "));
433 		if (pname_known(profile))
434 			printf("%s %s\n", pname(profile), p[2] & 1 ? _("(current)"):"");
435 		else
436 			printf("0x%04X %s\n", profile, p[2] & 1 ? _("(current)"):"");
437 		p += 4;
438 	}
439 	return (curprofile);
440 }
441 
442 EXPORT int
get_proflist(scgp,wp,cdp,dvdp,dvdplusp,ddcdp)443 get_proflist(scgp, wp, cdp, dvdp, dvdplusp, ddcdp)
444 	SCSI	*scgp;
445 	BOOL	*wp;
446 	BOOL	*cdp;
447 	BOOL	*dvdp;
448 	BOOL	*dvdplusp;
449 	BOOL	*ddcdp;
450 {
451 	Uchar	cbuf[1024];
452 	Uchar	*p;
453 	int	flen;
454 	int	curprofile;
455 	int	profile;
456 	int	i;
457 	int	n;
458 	BOOL	wr	= FALSE;
459 	BOOL	cd	= FALSE;
460 	BOOL	dvd	= FALSE;
461 	BOOL	dvdplus	= FALSE;
462 	BOOL	ddcd	= FALSE;
463 
464 	flen = get_profiles(scgp, (caddr_t)cbuf, sizeof (cbuf));
465 	if (flen < 0)
466 		return (-1);
467 
468 	p = cbuf;
469 	if (xdebug > 1)
470 		scg_prbytes(_("Features: "), cbuf, flen);
471 
472 	curprofile = a_to_u_2_byte(&p[6]);
473 	if (xdebug > 0)
474 		printf(_("feature len: %d current profile 0x%04X\n"),
475 				flen, curprofile);
476 
477 	p += 8;		/* Skip feature header	*/
478 	n = p[3];	/* Additional length	*/
479 	n /= 4;
480 	p += 4;
481 
482 	for (i = 0; i < n; i++) {
483 		profile = a_to_u_2_byte(p);
484 		p += 4;
485 		if (profile >= 0x0008 && profile < 0x0010)
486 			cd = TRUE;
487 		if (profile > 0x0008 && profile < 0x0010)
488 			wr = TRUE;
489 
490 		if (profile >= 0x0010 && profile < 0x0018)
491 			dvd = TRUE;
492 		if (profile > 0x0010 && profile < 0x0018)
493 			wr = TRUE;
494 
495 		if (profile >= 0x0018 && profile < 0x0020)
496 			dvdplus = TRUE;
497 		if (profile > 0x0018 && profile < 0x0020)
498 			wr = TRUE;
499 
500 		if (profile >= 0x0020 && profile < 0x0028)
501 			ddcd = TRUE;
502 		if (profile > 0x0020 && profile < 0x0028)
503 			wr = TRUE;
504 	}
505 	if (wp)
506 		*wp	= wr;
507 	if (cdp)
508 		*cdp	= cd;
509 	if (dvdp)
510 		*dvdp	= dvd;
511 	if (dvdplusp)
512 		*dvdplusp = dvdplus;
513 	if (ddcdp)
514 		*ddcdp	= ddcd;
515 
516 	return (curprofile);
517 }
518 
519 EXPORT int
get_wproflist(scgp,cdp,dvdp,dvdplusp,ddcdp)520 get_wproflist(scgp, cdp, dvdp, dvdplusp, ddcdp)
521 	SCSI	*scgp;
522 	BOOL	*cdp;
523 	BOOL	*dvdp;
524 	BOOL	*dvdplusp;
525 	BOOL	*ddcdp;
526 {
527 	Uchar	cbuf[1024];
528 	Uchar	*p;
529 	int	flen;
530 	int	curprofile;
531 	int	profile;
532 	int	i;
533 	int	n;
534 	BOOL	cd	= FALSE;
535 	BOOL	dvd	= FALSE;
536 	BOOL	dvdplus	= FALSE;
537 	BOOL	ddcd	= FALSE;
538 
539 	flen = get_profiles(scgp, (caddr_t)cbuf, sizeof (cbuf));
540 	if (flen < 0)
541 		return (-1);
542 	p = cbuf;
543 	curprofile = a_to_u_2_byte(&p[6]);
544 
545 	p += 8;		/* Skip feature header	*/
546 	n = p[3];	/* Additional length	*/
547 	n /= 4;
548 	p += 4;
549 
550 	for (i = 0; i < n; i++) {
551 		profile = a_to_u_2_byte(p);
552 		p += 4;
553 		if (profile > 0x0008 && profile < 0x0010)
554 			cd = TRUE;
555 		if (profile > 0x0010 && profile < 0x0018)
556 			dvd = TRUE;
557 		if (profile > 0x0018 && profile < 0x0020)
558 			dvdplus = TRUE;
559 		if (profile > 0x0020 && profile < 0x0028)
560 			ddcd = TRUE;
561 	}
562 	if (cdp)
563 		*cdp	= cd;
564 	if (dvdp)
565 		*dvdp	= dvd;
566 	if (dvdplusp)
567 		*dvdplusp = dvdplus;
568 	if (ddcdp)
569 		*ddcdp	= ddcd;
570 
571 	return (curprofile);
572 }
573 
574 EXPORT int
get_mediatype(scgp)575 get_mediatype(scgp)
576 	SCSI	*scgp;
577 {
578 	int	profile = get_curprofile(scgp);
579 
580 	if (profile < 0x08)
581 		return (MT_NONE);
582 	if (profile >= 0x08 && profile < 0x10)
583 		return (MT_CD);
584 	if (profile >= 0x10 && profile < 0x40)
585 		return (MT_DVD);
586 	if (profile >= 0x40 && profile < 0x50)
587 		return (MT_BD);
588 	if (profile >= 0x50 && profile < 0x60)
589 		return (MT_HDDVD);
590 
591 	return (MT_NONE);
592 }
593 
594 EXPORT int
get_singlespeed(mt)595 get_singlespeed(mt)
596 	int	mt;
597 {
598 	switch (mt) {
599 
600 	case MT_CD:
601 		return (176);
602 
603 	case MT_DVD:
604 		return (1385);
605 
606 	case MT_BD:
607 		return (4495);
608 
609 	case MT_HDDVD:
610 		return (4495);	/* XXX ??? */
611 
612 	case MT_NONE:
613 	default:
614 		return (1);
615 	}
616 }
617 
618 EXPORT float
get_secsps(mt)619 get_secsps(mt)
620 	int	mt;
621 {
622 	switch (mt) {
623 
624 	case MT_CD:
625 		return ((float)75.0);
626 
627 	case MT_DVD:
628 		return ((float)676.27);
629 
630 	case MT_BD:
631 		return ((float)2195.07);
632 
633 	case MT_HDDVD:
634 		return ((float)2195.07);	/* XXX ??? */
635 
636 	case MT_NONE:
637 	default:
638 		return ((float)75.0);
639 	}
640 }
641 
642 EXPORT char *
get_mclassname(mt)643 get_mclassname(mt)
644 	int	mt;
645 {
646 	switch (mt) {
647 
648 	case MT_CD:
649 		return ("CD");
650 
651 	case MT_DVD:
652 		return ("DVD");
653 
654 	case MT_BD:
655 		return ("BD");
656 
657 	case MT_HDDVD:
658 		return ("HD-DVD");
659 
660 	case MT_NONE:
661 	default:
662 		return ("NONE");
663 	}
664 }
665 
666 /*
667  * Guessed blocking factor based on media type
668  */
669 EXPORT int
get_blf(mt)670 get_blf(mt)
671 	int	mt;
672 {
673 	switch (mt) {
674 
675 	case MT_DVD:
676 		return (16);
677 
678 	case MT_BD:
679 		return (32);
680 
681 	case MT_HDDVD:
682 		return (32);	/* XXX ??? */
683 
684 	default:
685 		return (1);
686 	}
687 }
688 
689 LOCAL int
scsi_get_performance(scgp,bp,cnt,ndesc,type,datatype)690 scsi_get_performance(scgp, bp, cnt, ndesc, type, datatype)
691 	SCSI	*scgp;
692 	caddr_t	bp;
693 	int	cnt;
694 	int	ndesc;
695 	int	type;
696 	int	datatype;
697 {
698 	register struct	scg_cmd	*scmd = scgp->scmd;
699 
700 	fillbytes((caddr_t) scmd, sizeof (*scmd), '\0');
701 	scmd->addr = bp;
702 	scmd->size = cnt;
703 	scmd->flags = SCG_RECV_DATA | SCG_DISRE_ENA;
704 	scmd->cdb_len = SC_G5_CDBLEN;
705 	scmd->sense_len = CCS_SENSE_LEN;
706 	scmd->cdb.g1_cdb.cmd = 0xAC;
707 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
708 	scmd->cdb.cmd_cdb[1] |= datatype & 0x1F;
709 	scmd->cdb.cmd_cdb[9] = ndesc;
710 	scmd->cdb.cmd_cdb[10] = type;
711 
712 	scgp->cmdname = "get performance";
713 
714 	return (scg_cmd(scgp));
715 }
716 
717 
718 EXPORT int
scsi_get_perf_maxspeed(scgp,readp,writep,endp)719 scsi_get_perf_maxspeed(scgp, readp, writep, endp)
720 	SCSI	*scgp;
721 	Ulong	*readp;
722 	Ulong	*writep;
723 	Ulong	*endp;
724 {
725 	register struct	scg_cmd	*scmd = scgp->scmd;
726 	struct mmc_performance_header	*ph;
727 	struct mmc_write_speed		*wsp;
728 #define	MAX_AMT	100
729 	char buffer[8 + MAX_AMT*16];
730 	Ulong	ul;
731 	int	amt;
732 	int	i;
733 	int	mt = 0;
734 	int	ssp = 1;
735 	char	*mname = NULL;
736 
737 	if (xdebug != 0) {
738 		mt = get_mediatype(scgp);
739 		ssp = get_singlespeed(mt);
740 		mname = get_mclassname(mt);
741 	}
742 	fillbytes((caddr_t) buffer, sizeof (buffer), '\0');
743 	ph = (struct mmc_performance_header *)buffer;
744 	if (scsi_get_performance(scgp, buffer, 8+16, 1, 0x03, 0) < 0)
745 		return (-1);
746 
747 	amt = (a_to_4_byte(ph->p_datalen) -4)/sizeof (struct mmc_write_speed);
748 	if (amt < 1)
749 		amt = 1;
750 	if (amt > MAX_AMT)
751 		amt = MAX_AMT;
752 	if (scsi_get_performance(scgp, buffer, 8+amt*16, amt, 0x03, 0) < 0)
753 		return (-1);
754 
755 #ifdef	XDEBUG
756 	error(_("Bytes: %d\n"), scmd->size - scg_getresid(scgp));
757 	error(_("header: %ld\n"), a_to_4_byte(buffer) + 4);
758 #endif
759 
760 	ph = (struct mmc_performance_header *)buffer;
761 	wsp = (struct mmc_write_speed *)(((char *)ph) +
762 				sizeof (struct mmc_performance_header));
763 
764 	ul = a_to_u_4_byte(wsp->end_lba);
765 	if (endp)
766 		*endp = ul;
767 
768 	ul = a_to_u_4_byte(wsp->read_speed);
769 	if (readp)
770 		*readp = ul;
771 
772 	ul = a_to_u_4_byte(wsp->write_speed);
773 	if (writep)
774 		*writep = ul;
775 
776 	wsp = (struct mmc_write_speed *)(((char *)ph) +
777 				sizeof (struct mmc_performance_header));
778 
779 	i = (a_to_4_byte(buffer) -4)/sizeof (struct mmc_write_speed);
780 	if (i > scmd->cdb.cmd_cdb[9])
781 		i = scmd->cdb.cmd_cdb[9];
782 	if (xdebug > 0)
783 		error(_("MaxSpeed Nperf:   %d\n"), i);
784 	if (xdebug != 0) for (; --i >= 0; wsp++) {
785 		ul = a_to_u_4_byte(wsp->end_lba);
786 		error(_("End LBA:     %7lu\n"), ul);
787 		ul = a_to_u_4_byte(wsp->read_speed);
788 		error(_("Read Speed:  %7lu == %lux %s\n"), ul, ul/ssp, mname);
789 		ul = a_to_u_4_byte(wsp->write_speed);
790 		error(_("Write Speed: %7lu == %lux %s\n"), ul, ul/ssp, mname);
791 		error("\n");
792 	}
793 #ifdef	XDEBUG
794 	scg_prbytes(_("Performance data:"), (Uchar *)buffer, scmd->size - scg_getresid(scgp));
795 #endif
796 
797 	return (0);
798 #undef	MAX_AMT
799 }
800 
801 EXPORT int
scsi_get_perf_curspeed(scgp,readp,writep,endp)802 scsi_get_perf_curspeed(scgp, readp, writep, endp)
803 	SCSI	*scgp;
804 	Ulong	*readp;
805 	Ulong	*writep;
806 	Ulong	*endp;
807 {
808 	register struct	scg_cmd	*scmd = scgp->scmd;
809 	struct mmc_performance_header	*ph;
810 	struct mmc_performance		*perfp;
811 #define	MAX_AMT	100
812 	char buffer[8 + MAX_AMT*16];
813 	Ulong	ul;
814 	Ulong	end;
815 	Ulong	speed;
816 	int	amt;
817 	int	i;
818 	int	mt = 0;
819 	int	ssp = 1;
820 	char	*mname = NULL;
821 
822 	if (xdebug != 0) {
823 		mt = get_mediatype(scgp);
824 		ssp = get_singlespeed(mt);
825 		mname = get_mclassname(mt);
826 	}
827 
828 	if (endp || writep) {
829 		fillbytes((caddr_t) buffer, sizeof (buffer), '\0');
830 		scgp->silent++;
831 		if (scsi_get_performance(scgp, buffer, 8+16, 1, 0x00, 0x04) < 0) {
832 			scgp->silent--;
833 			goto doread;
834 		}
835 		scgp->silent--;
836 
837 		ph = (struct mmc_performance_header *)buffer;
838 		amt = (a_to_4_byte(ph->p_datalen) -4)/sizeof (struct mmc_performance);
839 		if (amt < 1)
840 			amt = 1;
841 		if (amt > MAX_AMT)
842 			amt = MAX_AMT;
843 
844 		if (scsi_get_performance(scgp, buffer, 8+16*amt, amt, 0x00, 0x04) < 0)
845 			return (-1);
846 
847 #ifdef	XDEBUG
848 		error(_("Bytes: %d\n"), scmd->size - scg_getresid(scgp));
849 		error(_("header: %ld\n"), a_to_4_byte(buffer) + 4);
850 #endif
851 
852 		ph = (struct mmc_performance_header *)buffer;
853 		perfp = (struct mmc_performance *)(((char *)ph) +
854 				sizeof (struct mmc_performance_header));
855 
856 		i = (a_to_4_byte(buffer) -4)/sizeof (struct mmc_performance);
857 		if (i > amt)
858 			i = amt;
859 		end = 0;
860 		speed = 0;
861 		for (; --i >= 0; perfp++) {
862 			ul = a_to_u_4_byte(perfp->end_lba);
863 			if (ul > end) {
864 				end = ul;
865 				ul = a_to_u_4_byte(perfp->end_perf);
866 				speed = ul;
867 			}
868 		}
869 
870 		if (endp)
871 			*endp = end;
872 
873 		if (writep)
874 			*writep = speed;
875 
876 		perfp = (struct mmc_performance *)(((char *)ph) +
877 				sizeof (struct mmc_performance_header));
878 		i = (a_to_4_byte(buffer) -4)/sizeof (struct mmc_performance);
879 		if (i > scmd->cdb.cmd_cdb[9])
880 			i = scmd->cdb.cmd_cdb[9];
881 		if (xdebug > 1)
882 			error(_("CurSpeed Writeperf: %d\n"), i);
883 		else if (xdebug < 0)
884 			error(_("Write Performance:\n"));
885 		if (xdebug != 0) for (; --i >= 0; perfp++) {
886 			ul = a_to_u_4_byte(perfp->start_lba);
887 			error(_("START LBA:   %7lu\n"), ul);
888 			ul = a_to_u_4_byte(perfp->end_lba);
889 			error(_("End LBA:     %7lu\n"), ul);
890 			ul = a_to_u_4_byte(perfp->start_perf);
891 			error(_("Start Perf:  %7lu == %lux %s\n"), ul, ul/ssp, mname);
892 			ul = a_to_u_4_byte(perfp->end_perf);
893 			error(_("END Perf:    %7lu == %lux %s\n"), ul, ul/ssp, mname);
894 			error("\n");
895 		}
896 #ifdef	XDEBUG
897 		scg_prbytes(_("Performance data:"), (Uchar *)buffer, scmd->size - scg_getresid(scgp));
898 #endif
899 	}
900 doread:
901 	if (readp) {
902 		fillbytes((caddr_t) buffer, sizeof (buffer), '\0');
903 		scgp->silent++;
904 		if (scsi_get_performance(scgp, buffer, 8+16, 1, 0x00, 0x00) < 0) {
905 			scgp->silent--;
906 			return (-1);
907 		}
908 		scgp->silent--;
909 
910 		ph = (struct mmc_performance_header *)buffer;
911 		amt = (a_to_4_byte(ph->p_datalen) -4)/sizeof (struct mmc_performance);
912 		if (amt < 1)
913 			amt = 1;
914 		if (amt > MAX_AMT)
915 			amt = MAX_AMT;
916 
917 		if (scsi_get_performance(scgp, buffer, 8+16*amt, amt, 0x00, 0x00) < 0)
918 			return (-1);
919 
920 #ifdef	XDEBUG
921 		error(_("Bytes: %d\n"), scmd->size - scg_getresid(scgp));
922 		error(_("header: %ld\n"), a_to_4_byte(buffer) + 4);
923 #endif
924 
925 		ph = (struct mmc_performance_header *)buffer;
926 		perfp = (struct mmc_performance *)(((char *)ph) +
927 				sizeof (struct mmc_performance_header));
928 
929 		i = (a_to_4_byte(buffer) -4)/sizeof (struct mmc_performance);
930 		if (i > amt)
931 			i = amt;
932 		end = 0;
933 		speed = 0;
934 		for (; --i >= 0; perfp++) {
935 			ul = a_to_u_4_byte(perfp->end_lba);
936 			if (ul > end) {
937 				end = ul;
938 				ul = a_to_u_4_byte(perfp->end_perf);
939 				speed = ul;
940 			}
941 		}
942 
943 		if (readp)
944 			*readp = speed;
945 
946 		i = (a_to_4_byte(buffer) -4)/sizeof (struct mmc_performance);
947 		if (i > scmd->cdb.cmd_cdb[9])
948 			i = scmd->cdb.cmd_cdb[9];
949 		if (xdebug > 1)
950 			error(_("CurSpeed Readperf: %d\n"), i);
951 		else if (xdebug < 0)
952 			error(_("Read Performance:\n"));
953 		if (xdebug != 0) for (; --i >= 0; perfp++) {
954 			ul = a_to_u_4_byte(perfp->start_lba);
955 			error(_("START LBA:   %7lu\n"), ul);
956 			ul = a_to_u_4_byte(perfp->end_lba);
957 			error(_("End LBA:     %7lu\n"), ul);
958 			ul = a_to_u_4_byte(perfp->start_perf);
959 			error(_("Start Perf:  %7lu == %lux %s\n"), ul, ul/ssp, mname);
960 			ul = a_to_u_4_byte(perfp->end_perf);
961 			error(_("END Perf:    %7lu == %lux %s\n"), ul, ul/ssp, mname);
962 			error("\n");
963 		}
964 #ifdef	XDEBUG
965 		scg_prbytes(_("Performance data:"), (Uchar *)buffer, scmd->size - scg_getresid(scgp));
966 #endif
967 	}
968 
969 	return (0);
970 }
971 
972 LOCAL int
scsi_set_streaming(scgp,readp,writep,endp)973 scsi_set_streaming(scgp, readp, writep, endp)
974 	SCSI	*scgp;
975 	Ulong	*readp;
976 	Ulong	*writep;
977 	Ulong	*endp;
978 {
979 	register struct	scg_cmd	*scmd = scgp->scmd;
980 	struct mmc_streaming	str;
981 	struct mmc_streaming	*sp = &str;
982 
983 	fillbytes((caddr_t) scmd, sizeof (*scmd), '\0');
984 	scmd->addr = (caddr_t) sp;
985 	scmd->size = sizeof (*sp);
986 	scmd->flags = SCG_DISRE_ENA;
987 	scmd->cdb_len = SC_G5_CDBLEN;
988 	scmd->sense_len = CCS_SENSE_LEN;
989 	scmd->cdb.g5_cdb.cmd = 0xB6;
990 	scmd->cdb.g5_cdb.lun = scg_lun(scgp);
991 	i_to_2_byte(&scmd->cdb.cmd_cdb[9], sizeof (*sp)); /* Sz not G5 alike */
992 
993 	scgp->cmdname = "set streaming";
994 
995 	fillbytes(sp, sizeof (*sp), '\0');
996 	if (endp)
997 		i_to_4_byte(sp->end_lba, *endp);
998 	else
999 		i_to_4_byte(sp->end_lba, 0x7FFFFFFF);
1000 
1001 	if (readp)
1002 		i_to_4_byte(sp->read_size, *readp);
1003 	else
1004 		i_to_4_byte(sp->read_size, 0x7FFFFFFF);
1005 
1006 	if (writep)
1007 		i_to_4_byte(sp->write_size, *writep);
1008 	else
1009 		i_to_4_byte(sp->write_size, 0x7FFFFFFF);
1010 
1011 	i_to_4_byte(sp->read_time, 1000);
1012 	i_to_4_byte(sp->write_time, 1000);
1013 
1014 #ifdef	DEBUG
1015 	scg_prbytes(_("Streaming data:"), (Uchar *)sp, sizeof (*sp));
1016 #endif
1017 
1018 	return (scg_cmd(scgp));
1019 }
1020 
1021 /*
1022  * set speed using the streaming descriptors
1023  */
1024 EXPORT int
speed_select_mdvd(scgp,readspeed,writespeed)1025 speed_select_mdvd(scgp, readspeed, writespeed)
1026 	SCSI	*scgp;
1027 	int	readspeed;
1028 	int	writespeed;
1029 {
1030 	Ulong	end_lba = 0x7FFFFFFF;
1031 	Ulong	wspeed = writespeed;
1032 
1033 	if (scsi_get_perf_maxspeed(scgp, (Ulong *)NULL, (Ulong *)NULL, &end_lba) < 0)
1034 		return (-1);
1035 
1036 	if (scsi_set_streaming(scgp, (Ulong *)NULL, &wspeed, &end_lba) < 0)
1037 		return (-1);
1038 
1039 	return (0);
1040 }
1041 
1042 
1043 LOCAL char *
fname(code)1044 fname(code)
1045 	Uint	code;
1046 {
1047 	UInt16_t	i;
1048 
1049 	for (i = 0; i < sizeof (fl) / sizeof (fl[0]); i++) {
1050 		if (code == fl[i].code)
1051 			return (fl[i].name);
1052 	}
1053 	return ("Unknown");
1054 }
1055 
1056 LOCAL char *
pname(code)1057 pname(code)
1058 	Uint	code;
1059 {
1060 	UInt16_t	i;
1061 
1062 	for (i = 0; i < sizeof (pl) / sizeof (pl[0]); i++) {
1063 		if (code == pl[i].code)
1064 			return (pl[i].name);
1065 	}
1066 	return ("Unknown");
1067 }
1068 
1069 LOCAL BOOL
fname_known(code)1070 fname_known(code)
1071 	Uint	code;
1072 {
1073 	UInt16_t	i;
1074 
1075 	for (i = 0; i < sizeof (fl) / sizeof (fl[0]); i++) {
1076 		if (code == fl[i].code)
1077 			return (TRUE);
1078 	}
1079 	return (FALSE);
1080 }
1081 
1082 LOCAL BOOL
pname_known(code)1083 pname_known(code)
1084 	Uint	code;
1085 {
1086 	UInt16_t	i;
1087 
1088 	for (i = 0; i < sizeof (pl) / sizeof (pl[0]); i++) {
1089 		if (code == pl[i].code)
1090 			return (TRUE);
1091 	}
1092 	return (FALSE);
1093 }
1094 
1095 EXPORT int
print_features(scgp)1096 print_features(scgp)
1097 	SCSI	*scgp;
1098 {
1099 	Uchar	fbuf[32 * 1024];
1100 	Uchar	*p;
1101 	Uchar	*pend;
1102 	int	amt;
1103 	int	flen;
1104 	int	feature;
1105 	int	i;
1106 
1107 	flen = get_conflen(scgp, 0, 0);
1108 	if (flen < 0)
1109 		return (-1);
1110 	if (sizeof (fbuf) < flen)
1111 		flen = sizeof (fbuf);
1112 
1113 	fillbytes(fbuf, sizeof (fbuf), '\0');
1114 	scgp->silent++;
1115 	i = get_configuration(scgp, (char *)fbuf, sizeof (fbuf), 0, 0);
1116 	scgp->silent--;
1117 	if (i < 0)
1118 		return (-1);
1119 	amt = sizeof (fbuf) - scg_getresid(scgp);
1120 
1121 	p = fbuf;
1122 	pend = &p[sizeof (fbuf) - scg_getresid(scgp)];
1123 	flen = a_to_u_4_byte(p);
1124 	if ((flen+4) < amt)
1125 		amt = flen+4;
1126 	pend = &p[amt];
1127 	if (xdebug > 1)
1128 		scg_prbytes(_("Features: "), fbuf, amt);
1129 
1130 	feature = a_to_u_2_byte(&p[6]);
1131 	if (xdebug > 0)
1132 		printf(_("feature len: %d current profile 0x%04X len %lld\n"),
1133 				flen, feature, (Llong)(pend - p));
1134 
1135 	p = fbuf + 8;	/* Skip feature header	*/
1136 	while (p < pend) {
1137 		int	col;
1138 
1139 		col = 0;
1140 		feature = a_to_u_2_byte(p);
1141 		if (xdebug > 0)
1142 			col += printf(_("Feature: 0x%04X "), feature);
1143 		else
1144 			col += printf(_("Feature: "));
1145 		if (fname_known(feature))
1146 			col += printf("'%s' ", fname(feature));
1147 		else
1148 			col += printf("0x%04X ", feature);
1149 		col += printf("%s %s",
1150 			p[2] & 1 ? _("(current)"):"",
1151 			p[2] & 2 ? _("(persistent)"):"");
1152 
1153 		if (feature == 0x108)
1154 			col += printf(_("	Serial: '%.*s'"), p[3], &p[4]);
1155 		if (xdebug > 1 && p[3]) {
1156 			if (col < 50)
1157 				printf("%*s", 50-col, "");
1158 			scg_fprbytes(stdout, _(" Data: "), &p[4], p[3]);
1159 		} else {
1160 			printf("\n");
1161 		}
1162 		p += p[3];
1163 		p += 4;
1164 	}
1165 	return (0);
1166 }
1167 
1168 LOCAL char *fdt[] = {
1169 	"Reserved (0)",
1170 	"Unformated or Blank Media",
1171 	"Formatted Media",
1172 	"No Media Present or Unknown Capacity"
1173 };
1174 
1175 EXPORT void
print_format_capacities(scgp)1176 print_format_capacities(scgp)
1177 	SCSI	*scgp;
1178 {
1179 	Uchar	b[1024];
1180 	int	i;
1181 	Uchar	*p;
1182 
1183 	fillbytes(b, sizeof (b), '\0');
1184 	scgp->silent++;
1185 	i = read_format_capacities(scgp, (char *)b, sizeof (b));
1186 	scgp->silent--;
1187 	if (i < 0)
1188 		return;
1189 
1190 	i = b[3] + 4;
1191 	fillbytes(b, sizeof (b), '\0');
1192 	if (read_format_capacities(scgp, (char *)b, i) < 0)
1193 		return;
1194 
1195 	if (xdebug > 0) {
1196 		i = b[3] + 4;
1197 		scg_prbytes(_("Format cap: "), b, i);
1198 	}
1199 	i = b[3];
1200 	if (i > 0) {
1201 		int	cnt;
1202 		UInt32_t n1;
1203 		UInt32_t n2;
1204 		printf(_("\n    Capacity  Blklen/Sparesz.  Format-type  Type\n"));
1205 		for (p = &b[4]; i > 0; i -= 8, p += 8) {
1206 			cnt = 0;
1207 			n1 = a_to_u_4_byte(p);
1208 			n2 = a_to_u_3_byte(&p[5]);
1209 			printf("%12lu %16lu         0x%2.2X  %s\n",
1210 				(Ulong)n1, (Ulong)n2,
1211 				(p[4] >> 2) & 0x3F,
1212 				fdt[p[4] & 0x03]);
1213 		}
1214 	}
1215 }
1216 
1217 EXPORT int
get_format_capacities(scgp,bp,cnt)1218 get_format_capacities(scgp, bp, cnt)
1219 	SCSI	*scgp;
1220 	caddr_t	bp;
1221 	int	cnt;
1222 {
1223 	int			len = sizeof (struct scsi_format_cap_header);
1224 	struct scsi_format_cap_header	*hp;
1225 
1226 	fillbytes(bp, cnt, '\0');
1227 	if (cnt < len)
1228 		return (-1);
1229 	scgp->silent++;
1230 	if (read_format_capacities(scgp, bp, len) < 0) {
1231 		scgp->silent--;
1232 		return (-1);
1233 	}
1234 	scgp->silent--;
1235 
1236 	if (scg_getresid(scgp) > 0)
1237 		return (-1);
1238 
1239 	hp = (struct scsi_format_cap_header *)bp;
1240 	len = hp->len;
1241 	len += sizeof (struct scsi_format_cap_header);
1242 	while (len > cnt)
1243 		len -= sizeof (struct scsi_format_cap_desc);
1244 
1245 	if (read_format_capacities(scgp, bp, len) < 0)
1246 		return (-1);
1247 
1248 	len -= scg_getresid(scgp);
1249 	return (len);
1250 }
1251 
1252 EXPORT int
read_format_capacities(scgp,bp,cnt)1253 read_format_capacities(scgp, bp, cnt)
1254 	SCSI	*scgp;
1255 	caddr_t	bp;
1256 	int	cnt;
1257 {
1258 	register struct	scg_cmd	*scmd = scgp->scmd;
1259 
1260 	fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1261 	scmd->addr = bp;
1262 	scmd->size = cnt;
1263 	scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1264 	scmd->cdb_len = SC_G1_CDBLEN;
1265 	scmd->sense_len = CCS_SENSE_LEN;
1266 	scmd->cdb.g1_cdb.cmd = 0x23;
1267 	scmd->cdb.g1_cdb.lun = scg_lun(scgp);
1268 	g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1269 
1270 	scgp->cmdname = "read_format_capacities";
1271 
1272 	return (scg_cmd(scgp));
1273 }
1274 
1275 EXPORT void
przone(rp)1276 przone(rp)
1277 	struct rzone_info *rp;
1278 {
1279 	int	rsize = a_to_2_byte(rp->data_len)+2;
1280 
1281 	if (rsize < 12)
1282 		return;
1283 	printf(_("rzone size:         %d\n"), rsize);
1284 	printf(_("rzone number:       %d\n"), rp->rzone_num_msb * 256 + rp->rzone_num_lsb);
1285 	printf(_("border number:      %d\n"), rp->border_num_msb * 256 + rp->border_num_lsb);
1286 	printf(_("ljrs:               %d\n"), rp->ljrs);
1287 	printf(_("track mode:         %d copy: %d\n"), rp->trackmode, rp->copy);
1288 	printf(_("damage:             %d\n"), rp->damage);
1289 	printf(_("reserved track:     %d blank: %d incremental: %d fp: %d\n"),
1290 						rp->rt, rp->blank,
1291 						rp->incremental, rp->fp);
1292 	printf(_("data mode:          %d\n"), rp->datamode);
1293 	printf(_("lra valid:          %d\n"), rp->lra_v);
1294 	printf(_("nwa valid:          %d\n"), rp->nwa_v);
1295 	printf(_("rzone start:        %ld\n"), a_to_4_byte(rp->rzone_start));
1296 	printf(_("next wr addr:       %ld\n"), a_to_4_byte(rp->next_recordable_addr));
1297 	printf(_("free blocks:        %ld\n"), a_to_4_byte(rp->free_blocks));
1298 	printf(_("blocking factor:    %ld\n"), a_to_4_byte(rp->block_factor));
1299 	printf(_("rzone size:         %ld\n"), a_to_4_byte(rp->rzone_size));
1300 	printf(_("last recorded addr: %ld\n"), a_to_4_byte(rp->last_recorded_addr));
1301 	if (rsize < 40)
1302 		return;
1303 	printf(_("read compat lba:    %ld\n"), a_to_4_byte(rp->read_compat_lba));
1304 	if (rsize < 44)
1305 		return;
1306 	printf(_("next layerjmp addr: %ld\n"), a_to_4_byte(rp->next_layer_jump));
1307 	if (rsize < 48)
1308 		return;
1309 	printf(_("last layerjmp addr: %ld\n"), a_to_4_byte(rp->last_layer_jump));
1310 }
1311 
1312 EXPORT int
get_diskinfo(scgp,dip,cnt)1313 get_diskinfo(scgp, dip, cnt)
1314 	SCSI		*scgp;
1315 	struct disk_info *dip;
1316 	int		cnt;
1317 {
1318 	int	len;
1319 	int	ret;
1320 
1321 	fillbytes((caddr_t)dip, cnt, '\0');
1322 
1323 	/*
1324 	 * Used to be 2 instead of 4 (now). But some Y2k ATAPI drives as used
1325 	 * by IOMEGA create a DMA overrun if we try to transfer only 2 bytes.
1326 	 */
1327 	if (read_disk_info(scgp, (caddr_t)dip, 4) < 0)
1328 		return (-1);
1329 	len = a_to_u_2_byte(dip->data_len);
1330 	len += 2;
1331 	if (len > cnt)
1332 		len = cnt;
1333 	ret = read_disk_info(scgp, (caddr_t)dip, len);
1334 
1335 #ifdef	DEBUG
1336 	if (lverbose > 1)
1337 		scg_prbytes(_("Disk info:"), (Uchar *)dip,
1338 				len-scg_getresid(scgp));
1339 #endif
1340 	return (ret);
1341 }
1342 
1343 #define	IS(what, flag)		printf(_("Disk Is %s%s\n"), flag?"":_("not "), what);
1344 
1345 LOCAL	char	res[] = "reserved";
1346 
1347 EXPORT char *
get_ses_type(ses_type)1348 get_ses_type(ses_type)
1349 	int	ses_type;
1350 {
1351 static	char	ret[16];
1352 
1353 	switch (ses_type) {
1354 
1355 	case SES_DA_ROM:	return ("CD-DA or CD-ROM");
1356 	case SES_CDI:		return ("CDI");
1357 	case SES_XA:		return ("CD-ROM XA");
1358 	case SES_UNDEF:		return ("undefined");
1359 	default:
1360 				js_snprintf(ret, sizeof (ret), "%s: 0x%2.2X",
1361 							res, ses_type);
1362 				return (ret);
1363 	}
1364 }
1365 
1366 EXPORT void
print_diskinfo(dip,is_cd)1367 print_diskinfo(dip, is_cd)
1368 	struct disk_info	*dip;
1369 	BOOL			is_cd;
1370 {
1371 static	char *dt_name[] = { "standard", "track resources", "POW resources", res, res, res, res, res };
1372 static	char *ds_name[] = { "empty", "incomplete/appendable", "complete", "illegal" };
1373 static	char *ss_name[] = { "empty", "incomplete/appendable", "illegal", "complete", };
1374 static	char *fd_name[] = { "none", "incomplete", "in progress", "completed", };
1375 
1376 	IS(_("erasable"), dip->erasable);
1377 	printf(_("data type:                %s\n"), dt_name[dip->dtype]);
1378 	printf(_("disk status:              %s\n"), ds_name[dip->disk_status]);
1379 	printf(_("session status:           %s\n"), ss_name[dip->sess_status]);
1380 	printf(_("BG format status:         %s\n"), fd_name[dip->bg_format_stat]);
1381 	printf(_("first track:              %d\n"),
1382 		dip->first_track);
1383 	printf(_("number of sessions:       %d\n"),
1384 		dip->numsess + dip->numsess_msb * 256);
1385 	printf(_("first track in last sess: %d\n"),
1386 		dip->first_track_ls + dip->first_track_ls_msb * 256);
1387 	printf(_("last track in last sess:  %d\n"),
1388 		dip->last_track_ls + dip->last_track_ls_msb * 256);
1389 	IS(_("unrestricted"), dip->uru);
1390 	printf(_("Disk type: "));
1391 	if (is_cd) {
1392 		printf("%s", get_ses_type(dip->disk_type));
1393 	} else {
1394 		printf(_("DVD, HD-DVD or BD"));
1395 	}
1396 	printf("\n");
1397 	if (dip->did_v)
1398 		printf(_("Disk id: 0x%lX\n"), a_to_u_4_byte(dip->disk_id));
1399 
1400 	if (is_cd) {
1401 		printf(_("last start of lead in: %ld\n"),
1402 			msf_to_lba(dip->last_lead_in[1],
1403 			dip->last_lead_in[2],
1404 			dip->last_lead_in[3], FALSE));
1405 		printf(_("last start of lead out: %ld\n"),
1406 			msf_to_lba(dip->last_lead_out[1],
1407 			dip->last_lead_out[2],
1408 			dip->last_lead_out[3], TRUE));
1409 	}
1410 
1411 	if (dip->dbc_v)
1412 		printf(_("Disk bar code: 0x%lX%lX\n"),
1413 			a_to_u_4_byte(dip->disk_barcode),
1414 			a_to_u_4_byte(&dip->disk_barcode[4]));
1415 
1416 	if (dip->dac_v)
1417 		printf(_("Disk appl. code: %d\n"), dip->disk_appl_code);
1418 
1419 	if (dip->num_opc_entries > 0) {
1420 		printf(_("OPC table:\n"));
1421 	}
1422 }
1423 
1424 EXPORT int
prdiskstatus(scgp,dp,is_cd)1425 prdiskstatus(scgp, dp, is_cd)
1426 	SCSI	*scgp;
1427 	cdr_t	*dp;
1428 	BOOL	is_cd;
1429 {
1430 	struct disk_info	di;
1431 	struct rzone_info	rz;
1432 	int			sessions;
1433 	int			track;
1434 	int			tracks;
1435 	int			t;
1436 	int			s;
1437 	long			raddr;
1438 	long			lastaddr = -1;
1439 	long			lastsess = -1;
1440 	long			leadout = -1;
1441 	long			lo_sess = 0;
1442 	long			nwa = -1;
1443 	long			rsize = -1;
1444 	long			border_size = -1;
1445 	int			profile;
1446 
1447 	profile = get_curprofile(scgp);
1448 	if (profile > 0) {
1449 		int mt = get_mediatype(scgp);
1450 
1451 		printf(_("Mounted media class:      %s\n"),
1452 				get_mclassname(mt));
1453 		if (pname_known(profile)) {
1454 			printf(_("Mounted media type:       %s\n"),
1455 				pname(profile));
1456 		}
1457 	}
1458 	get_diskinfo(scgp, &di, sizeof (di));
1459 	print_diskinfo(&di, is_cd);
1460 
1461 	sessions = di.numsess + di.numsess_msb * 256;
1462 	tracks = di.last_track_ls + di.last_track_ls_msb * 256;
1463 
1464 	printf(_("\nTrack  Sess Type   Start Addr End Addr   Size\n"));
1465 	printf(_("==============================================\n"));
1466 	fillbytes((caddr_t)&rz, sizeof (rz), '\0');
1467 	for (t = di.first_track; t <= tracks; t++) {
1468 		fillbytes((caddr_t)&rz, sizeof (rz), '\0');
1469 		get_trackinfo(scgp, (caddr_t)&rz, TI_TYPE_TRACK, t, sizeof (rz));
1470 		if (lverbose > 1)
1471 			przone(&rz);
1472 		track = rz.rzone_num_lsb + rz.rzone_num_msb * 256;
1473 		s = rz.border_num_lsb + rz.border_num_msb * 256;
1474 		raddr = a_to_4_byte(rz.rzone_start);
1475 		if (rsize >= 0)
1476 			border_size = raddr - (lastaddr+rsize);
1477 		if (!rz.blank && s > lastsess) { /* First track in last sess ? */
1478 			lastaddr = raddr;
1479 			lastsess = s;
1480 		}
1481 		nwa = a_to_4_byte(rz.next_recordable_addr);
1482 		rsize = a_to_4_byte(rz.rzone_size);
1483 		if (!rz.blank) {
1484 			leadout = raddr + rsize;
1485 			lo_sess = s;
1486 		}
1487 		printf("%5d %5d %-6s %-10ld %-10ld %ld",
1488 			track, s,
1489 			rz.blank ? _("Blank") :
1490 				rz.trackmode & 4 ? _("Data") : _("Audio"),
1491 			raddr, raddr + rsize -1, rsize);
1492 		if (lverbose > 0)
1493 			printf(" %10ld", border_size);
1494 		printf("\n");
1495 	}
1496 	printf("\n");
1497 	if (lastaddr >= 0)
1498 		printf(_("Last session start address:         %ld\n"), lastaddr);
1499 	if (leadout >= 0)
1500 		printf(_("Last session leadout start address: %ld\n"), leadout);
1501 	if (rz.nwa_v) {
1502 		printf(_("Next writable address:              %ld\n"), nwa);
1503 		printf(_("Remaining writable size:            %ld\n"), rsize);
1504 	}
1505 
1506 	return (0);
1507 }
1508 
1509 EXPORT int
sessstatus(scgp,is_cd,offp,nwap)1510 sessstatus(scgp, is_cd, offp, nwap)
1511 	SCSI	*scgp;
1512 	BOOL	is_cd;
1513 	long	*offp;
1514 	long	*nwap;
1515 {
1516 	struct disk_info	di;
1517 	struct rzone_info	rz;
1518 	int			sessions;
1519 	int			track;
1520 	int			tracks;
1521 	int			t;
1522 	int			s;
1523 	long			raddr;
1524 	long			lastaddr = -1;
1525 	long			lastsess = -1;
1526 	long			leadout = -1;
1527 	long			lo_sess = 0;
1528 	long			nwa = -1;
1529 	long			rsize = -1;
1530 	long			border_size = -1;
1531 
1532 
1533 	if (get_diskinfo(scgp, &di, sizeof (di)) < 0)
1534 		return (-1);
1535 
1536 	sessions = di.numsess + di.numsess_msb * 256;
1537 	tracks = di.last_track_ls + di.last_track_ls_msb * 256;
1538 
1539 	fillbytes((caddr_t)&rz, sizeof (rz), '\0');
1540 	for (t = di.first_track; t <= tracks; t++) {
1541 		fillbytes((caddr_t)&rz, sizeof (rz), '\0');
1542 		if (get_trackinfo(scgp, (caddr_t)&rz, TI_TYPE_TRACK, t, sizeof (rz)) < 0)
1543 			return (-1);
1544 		track = rz.rzone_num_lsb + rz.rzone_num_msb * 256;
1545 		s = rz.border_num_lsb + rz.border_num_msb * 256;
1546 		raddr = a_to_4_byte(rz.rzone_start);
1547 		if (rsize >= 0)
1548 			border_size = raddr - (lastaddr+rsize);
1549 		if (!rz.blank && s > lastsess) { /* First track in last sess ? */
1550 			lastaddr = raddr;
1551 			lastsess = s;
1552 		}
1553 		nwa = a_to_4_byte(rz.next_recordable_addr);
1554 		rsize = a_to_4_byte(rz.rzone_size);
1555 		if (!rz.blank) {
1556 			leadout = raddr + rsize;
1557 			lo_sess = s;
1558 		}
1559 	}
1560 	if (lastaddr >= 0 && offp != NULL)
1561 		*offp = lastaddr;
1562 
1563 	if (rz.nwa_v && nwap != NULL)
1564 		*nwap = nwa;
1565 
1566 	return (0);
1567 }
1568 
1569 EXPORT void
print_performance_mmc(scgp)1570 print_performance_mmc(scgp)
1571 	SCSI	*scgp;
1572 {
1573 	Ulong	reads;
1574 	Ulong	writes;
1575 	Ulong	ends = 0x7FFFFFFF;
1576 	int	oxdebug = xdebug;
1577 
1578 	/*
1579 	 * Do not try to fail with old drives...
1580 	 */
1581 	if (get_curprofile(scgp) < 0)
1582 		return;
1583 
1584 	if (xdebug == 0)
1585 		xdebug = -1;
1586 
1587 	printf(_("\nCurrent performance according to MMC get performance:\n"));
1588 	scsi_get_perf_curspeed(scgp, &reads, &writes, &ends);
1589 
1590 	printf(_("\nMaximum performance according to MMC get performance:\n"));
1591 	scsi_get_perf_maxspeed(scgp, &reads, &writes, &ends);
1592 
1593 	xdebug = oxdebug;
1594 }
1595