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