2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)scsi_cdr.c 1.137 04/05/25 Copyright 1995-2004 J. Schilling */
15 * SCSI command functions for cdrecord
16 * covering pre-MMC standard functions up to MMC-2
18 * Copyright (c) 1995-2004 J. Schilling
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License version 2
23 * as published by the Free Software Foundation.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License along with
31 * this program; see the file COPYING. If not, write to the Free Software
32 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 * NOTICE: The Philips CDD 521 has several firmware bugs.
37 * One of them is not to respond to a SCSI selection
38 * within 200ms if the general load on the
39 * SCSI bus is high. To deal with this problem
40 * most of the SCSI commands are send with the
41 * SCG_CMD_RETRY flag enabled.
59 #include <usal/usalcmd.h>
60 #include <usal/scsidefs.h>
61 #include <usal/scsireg.h>
62 #include <usal/scsitransp.h>
66 #include "scsi_scan.h"
68 #define strbeg(s1, s2) (strstr((s2), (s1)) == (s2))
70 BOOL unit_ready(SCSI *usalp);
71 BOOL wait_unit_ready(SCSI *usalp, int secs);
72 BOOL scsi_in_progress(SCSI *usalp);
73 BOOL cdr_underrun(SCSI *usalp);
74 int test_unit_ready(SCSI *usalp);
75 int rezero_unit(SCSI *usalp);
76 int request_sense(SCSI *usalp);
77 int request_sense_b(SCSI *usalp, caddr_t bp, int cnt);
78 int inquiry(SCSI *usalp, caddr_t, int);
79 int read_capacity(SCSI *usalp);
80 void print_capacity(SCSI *usalp, FILE *f);
81 int scsi_load_unload(SCSI *usalp, int);
82 int scsi_prevent_removal(SCSI *usalp, int);
83 int scsi_start_stop_unit(SCSI *usalp, int, int, BOOL immed);
84 int scsi_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl);
85 int scsi_get_speed(SCSI *usalp, int *readspeedp, int *writespeedp);
86 int qic02(SCSI *usalp, int);
87 int write_xscsi(SCSI *usalp, caddr_t, long, long, int);
88 int write_xg0(SCSI *usalp, caddr_t, long, long, int);
89 int write_xg1(SCSI *usalp, caddr_t, long, long, int);
90 int write_xg5(SCSI *usalp, caddr_t, long, long, int);
91 int seek_scsi(SCSI *usalp, long addr);
92 int seek_g0(SCSI *usalp, long addr);
93 int seek_g1(SCSI *usalp, long addr);
94 int scsi_flush_cache(SCSI *usalp, BOOL immed);
95 int read_buffer(SCSI *usalp, caddr_t bp, int cnt, int mode);
96 int write_buffer(SCSI *usalp, char *buffer, long length, int mode,
97 int bufferid, long offset);
98 int read_subchannel(SCSI *usalp, caddr_t bp, int track, int cnt, int msf,
100 int read_toc(SCSI *usalp, caddr_t, int, int, int, int);
101 int read_toc_philips(SCSI *usalp, caddr_t, int, int, int, int);
102 int read_header(SCSI *usalp, caddr_t, long, int, int);
103 int read_disk_info(SCSI *usalp, caddr_t, int);
104 int read_track_info(SCSI *usalp, caddr_t, int type, int addr, int cnt);
105 int read_rzone_info(SCSI *usalp, caddr_t bp, int cnt);
106 int reserve_tr_rzone(SCSI *usalp, long size);
107 int read_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int addr, int layer,
109 int send_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int layer, int fmt);
110 int send_opc(SCSI *usalp, caddr_t, int cnt, int doopc);
111 int read_track_info_philips(SCSI *usalp, caddr_t, int, int);
112 int scsi_close_tr_session(SCSI *usalp, int type, int track, BOOL immed);
113 int read_master_cue(SCSI *usalp, caddr_t bp, int sheet, int cnt);
114 int send_cue_sheet(SCSI *usalp, caddr_t bp, long size);
115 int read_buff_cap(SCSI *usalp, long *, long *);
116 int scsi_blank(SCSI *usalp, long addr, int blanktype, BOOL immed);
117 int scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background);
118 int scsi_set_streaming(SCSI *usalp, caddr_t addr, int size);
119 BOOL allow_atapi(SCSI *usalp, BOOL new);
120 int mode_select(SCSI *usalp, Uchar *, int, int, int);
121 int mode_sense(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
122 int mode_select_sg0(SCSI *usalp, Uchar *, int, int, int);
123 int mode_sense_sg0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
124 int mode_select_g0(SCSI *usalp, Uchar *, int, int, int);
125 int mode_select_g1(SCSI *usalp, Uchar *, int, int, int);
126 int mode_sense_g0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
127 int mode_sense_g1(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
128 int read_tochdr(SCSI *usalp, cdr_t *, int *, int *);
129 int read_cdtext(SCSI *usalp);
130 int read_trackinfo(SCSI *usalp, int, long *, struct msf *, int *, int *,
132 int read_B0(SCSI *usalp, BOOL isbcd, long *b0p, long *lop);
133 int read_session_offset(SCSI *usalp, long *);
134 int read_session_offset_philips(SCSI *usalp, long *);
135 int sense_secsize(SCSI *usalp, int current);
136 int select_secsize(SCSI *usalp, int);
137 BOOL is_cddrive(SCSI *usalp);
138 BOOL is_unknown_dev(SCSI *usalp);
139 int read_scsi(SCSI *usalp, caddr_t, long, int);
140 int read_g0(SCSI *usalp, caddr_t, long, int);
141 int read_g1(SCSI *usalp, caddr_t, long, int);
142 BOOL getdev(SCSI *usalp, BOOL);
143 void printinq(SCSI *usalp, FILE *f);
144 void printdev(SCSI *usalp);
145 BOOL do_inquiry(SCSI *usalp, BOOL);
146 BOOL recovery_needed(SCSI *usalp, cdr_t *);
147 int scsi_load(SCSI *usalp, cdr_t *);
148 int scsi_unload(SCSI *usalp, cdr_t *);
149 int scsi_cdr_write(SCSI *usalp, caddr_t bp, long sectaddr, long size,
150 int blocks, BOOL islast);
151 struct cd_mode_page_2A * mmc_cap(SCSI *usalp, Uchar *modep);
152 void mmc_getval(struct cd_mode_page_2A *mp, BOOL *cdrrp, BOOL *cdwrp,
153 BOOL *cdrrwp, BOOL *cdwrwp, BOOL *dvdp, BOOL *dvdwp);
154 BOOL is_mmc(SCSI *usalp, BOOL *cdwp, BOOL *dvdwp);
155 BOOL mmc_check(SCSI *usalp, BOOL *cdrrp, BOOL *cdwrp, BOOL *cdrrwp,
156 BOOL *cdwrwp, BOOL *dvdp, BOOL *dvdwp);
157 static void print_speed(char *fmt, int val);
158 void print_capabilities(SCSI *usalp);
161 unit_ready(SCSI *usalp)
163 register struct usal_cmd *scmd = usalp->scmd;
165 if (test_unit_ready(usalp) >= 0) /* alles OK */
167 else if (scmd->error >= SCG_FATAL) /* nicht selektierbar */
170 if (usal_sense_key(usalp) == SC_UNIT_ATTENTION) {
171 if (test_unit_ready(usalp) >= 0) /* alles OK */
174 if ((usal_cmd_status(usalp) & ST_BUSY) != 0) {
176 * Busy/reservation_conflict
179 if (test_unit_ready(usalp) >= 0) /* alles OK */
182 if (usal_sense_key(usalp) == -1) { /* non extended Sense */
183 if (usal_sense_code(usalp) == 4) /* NOT_READY */
187 /* FALSE wenn NOT_READY */
188 return (usal_sense_key(usalp) != SC_NOT_READY);
192 wait_unit_ready(SCSI *usalp, int secs)
200 ret = test_unit_ready(usalp); /* eat up unit attention */
202 ret = test_unit_ready(usalp); /* got power on condition? */
205 if (ret >= 0) /* success that's enough */
209 for (i = 0; i < secs && (ret = test_unit_ready(usalp)) < 0; i++) {
210 if (usalp->scmd->scb.busy != 0) {
214 c = usal_sense_code(usalp);
215 k = usal_sense_key(usalp);
217 * Abort quickly if it does not make sense to wait.
218 * 0x30 == Cannot read medium
219 * 0x3A == Medium not present
221 if ((k == SC_NOT_READY && (c == 0x3A || c == 0x30)) ||
222 (k == SC_MEDIUM_ERROR)) {
223 if (usalp->silent <= 1)
224 usal_printerr(usalp);
237 scsi_in_progress(SCSI *usalp)
239 if (usal_sense_key(usalp) == SC_NOT_READY &&
241 * Logigal unit not ready operation/long_write in progress
243 usal_sense_code(usalp) == 0x04 &&
244 (usal_sense_qual(usalp) == 0x04 || /* CyberDr. "format in progress"*/
245 usal_sense_qual(usalp) == 0x07 || /* "operation in progress" */
246 usal_sense_qual(usalp) == 0x08)) { /* "long write in progress" */
249 if (usalp->silent <= 1)
250 usal_printerr(usalp);
256 cdr_underrun(SCSI *usalp)
258 if ((usal_sense_key(usalp) != SC_ILLEGAL_REQUEST &&
259 usal_sense_key(usalp) != SC_MEDIUM_ERROR))
262 if ((usal_sense_code(usalp) == 0x21 &&
263 (usal_sense_qual(usalp) == 0x00 || /* logical block address out of range */
264 usal_sense_qual(usalp) == 0x02)) || /* invalid address for write */
266 (usal_sense_code(usalp) == 0x0C &&
267 usal_sense_qual(usalp) == 0x09)) { /* write error - loss of streaming */
271 * XXX Bei manchen Brennern kommt mach dem der Brennvorgang bereits
272 * XXX eine Weile gelaufen ist ein 5/24/0 Invalid field in CDB.
273 * XXX Daher sollte man testen ob schon geschrieben wurde...
279 test_unit_ready(SCSI *usalp)
281 register struct usal_cmd *scmd = usalp->scmd;
283 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
284 scmd->addr = (caddr_t)0;
286 scmd->flags = SCG_DISRE_ENA | (usalp->silent ? SCG_SILENT:0);
287 scmd->cdb_len = SC_G0_CDBLEN;
288 scmd->sense_len = CCS_SENSE_LEN;
289 scmd->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY;
290 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
292 usalp->cmdname = "test unit ready";
294 return (usal_cmd(usalp));
298 rezero_unit(SCSI *usalp)
300 register struct usal_cmd *scmd = usalp->scmd;
302 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
303 scmd->addr = (caddr_t)0;
305 scmd->flags = SCG_DISRE_ENA;
306 scmd->cdb_len = SC_G0_CDBLEN;
307 scmd->sense_len = CCS_SENSE_LEN;
308 scmd->cdb.g0_cdb.cmd = SC_REZERO_UNIT;
309 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
311 usalp->cmdname = "rezero unit";
313 return (usal_cmd(usalp));
317 request_sense(SCSI *usalp)
319 char sensebuf[CCS_SENSE_LEN];
320 register struct usal_cmd *scmd = usalp->scmd;
323 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
324 scmd->addr = sensebuf;
325 scmd->size = sizeof (sensebuf);
326 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
327 scmd->cdb_len = SC_G0_CDBLEN;
328 scmd->sense_len = CCS_SENSE_LEN;
329 scmd->cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
330 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
331 scmd->cdb.g0_cdb.count = CCS_SENSE_LEN;
333 usalp->cmdname = "request_sense";
335 if (usal_cmd(usalp) < 0)
337 usal_prsense((Uchar *)sensebuf, CCS_SENSE_LEN - usal_getresid(usalp));
342 request_sense_b(SCSI *usalp, caddr_t bp, int cnt)
344 register struct usal_cmd *scmd = usalp->scmd;
347 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
350 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
351 scmd->cdb_len = SC_G0_CDBLEN;
352 scmd->sense_len = CCS_SENSE_LEN;
353 scmd->cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
354 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
355 scmd->cdb.g0_cdb.count = cnt;
357 usalp->cmdname = "request_sense";
359 if (usal_cmd(usalp) < 0)
365 inquiry(SCSI *usalp, caddr_t bp, int cnt)
367 register struct usal_cmd *scmd = usalp->scmd;
369 fillbytes(bp, cnt, '\0');
370 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
373 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
374 scmd->cdb_len = SC_G0_CDBLEN;
375 scmd->sense_len = CCS_SENSE_LEN;
376 scmd->cdb.g0_cdb.cmd = SC_INQUIRY;
377 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
378 scmd->cdb.g0_cdb.count = cnt;
380 usalp->cmdname = "inquiry";
382 if (usal_cmd(usalp) < 0)
385 usal_prbytes("Inquiry Data :", (Uchar *)bp, cnt - usal_getresid(usalp));
390 read_capacity(SCSI *usalp)
392 register struct usal_cmd *scmd = usalp->scmd;
394 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
395 scmd->addr = (caddr_t)usalp->cap;
396 scmd->size = sizeof (struct scsi_capacity);
397 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
398 scmd->cdb_len = SC_G1_CDBLEN;
399 scmd->sense_len = CCS_SENSE_LEN;
400 scmd->cdb.g1_cdb.cmd = 0x25; /* Read Capacity */
401 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
402 g1_cdblen(&scmd->cdb.g1_cdb, 0); /* Full Media */
404 usalp->cmdname = "read capacity";
406 if (usal_cmd(usalp) < 0) {
413 * c_bsize & c_baddr are signed Int32_t
414 * so we use signed int conversion here.
416 cbsize = a_to_4_byte(&usalp->cap->c_bsize);
417 cbaddr = a_to_4_byte(&usalp->cap->c_baddr);
418 usalp->cap->c_bsize = cbsize;
419 usalp->cap->c_baddr = cbaddr;
425 print_capacity(SCSI *usalp, FILE *f)
432 dkb = (usalp->cap->c_baddr+1.0) * (usalp->cap->c_bsize/1024.0);
435 prmb = dkb / 1000.0 * 1.024;
436 fprintf(f, "Capacity: %ld Blocks = %ld kBytes = %ld MBytes = %ld prMB\n",
437 (long)usalp->cap->c_baddr+1, kb, mb, prmb);
438 fprintf(f, "Sectorsize: %ld Bytes\n", (long)usalp->cap->c_bsize);
442 scsi_load_unload(SCSI *usalp, int load)
444 register struct usal_cmd *scmd = usalp->scmd;
446 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
447 scmd->flags = SCG_DISRE_ENA;
448 scmd->cdb_len = SC_G5_CDBLEN;
449 scmd->sense_len = CCS_SENSE_LEN;
450 scmd->cdb.g5_cdb.cmd = 0xA6;
451 scmd->cdb.g5_cdb.lun = usal_lun(usalp);
452 scmd->cdb.g5_cdb.addr[1] = load?3:2;
453 scmd->cdb.g5_cdb.count[2] = 0; /* slot # */
455 usalp->cmdname = "medium load/unload";
457 if (usal_cmd(usalp) < 0)
463 scsi_prevent_removal(SCSI *usalp, int prevent)
465 register struct usal_cmd *scmd = usalp->scmd;
467 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
468 scmd->flags = SCG_DISRE_ENA;
469 scmd->cdb_len = SC_G0_CDBLEN;
470 scmd->sense_len = CCS_SENSE_LEN;
471 scmd->cdb.g0_cdb.cmd = 0x1E;
472 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
473 scmd->cdb.g0_cdb.count = prevent & 1;
475 usalp->cmdname = "prevent/allow medium removal";
477 if (usal_cmd(usalp) < 0)
484 scsi_start_stop_unit(SCSI *usalp, int flg, int loej, BOOL immed)
486 register struct usal_cmd *scmd = usalp->scmd;
488 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
489 scmd->flags = SCG_DISRE_ENA;
490 scmd->cdb_len = SC_G0_CDBLEN;
491 scmd->sense_len = CCS_SENSE_LEN;
492 scmd->cdb.g0_cdb.cmd = 0x1B; /* Start Stop Unit */
493 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
494 scmd->cdb.g0_cdb.count = (flg ? 1:0) | (loej ? 2:0);
497 scmd->cdb.cmd_cdb[1] |= 0x01;
499 usalp->cmdname = "start/stop unit";
501 return (usal_cmd(usalp));
505 scsi_set_streaming(SCSI *usalp, caddr_t perf_desc, int size)
507 register struct usal_cmd *scmd = usalp->scmd;
509 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
510 scmd->addr = perf_desc;
512 scmd->flags = SCG_DISRE_ENA;
513 scmd->cdb_len = SC_G5_CDBLEN;
514 scmd->sense_len = CCS_SENSE_LEN;
515 scmd->cdb.g5_cdb.cmd = 0xB6;
516 scmd->cdb.cmd_cdb[11] = 0;
517 scmd->cdb.cmd_cdb[10] = size;
519 usalp->cmdname = "set streaming";
522 fprintf(stderr, "scsi_set_streaming\n");
523 if (usal_cmd(usalp) < 0)
529 scsi_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl)
531 register struct usal_cmd *scmd = usalp->scmd;
533 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
534 scmd->flags = SCG_DISRE_ENA;
535 scmd->cdb_len = SC_G5_CDBLEN;
536 scmd->sense_len = CCS_SENSE_LEN;
537 scmd->cdb.g5_cdb.cmd = 0xBB;
538 scmd->cdb.g5_cdb.lun = usal_lun(usalp);
541 i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], 0xFFFF);
543 i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], readspeed);
545 i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xFFFF);
547 i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], writespeed);
549 scmd->cdb.cmd_cdb[1] |= rotctl & 0x03;
551 usalp->cmdname = "set cd speed";
553 if (usal_cmd(usalp) < 0)
559 scsi_get_speed(SCSI *usalp, int *readspeedp, int *writespeedp)
561 struct cd_mode_page_2A *mp;
566 mp = mmc_cap(usalp, m); /* Get MMC capabilities in allocated mp */
569 return (-1); /* Pre SCSI-3/mmc drive */
571 val = a_to_u_2_byte(mp->cur_read_speed);
576 val = a_to_u_2_byte(mp->v3_cur_write_speed);
578 val = a_to_u_2_byte(mp->cur_write_speed);
587 qic02(SCSI *usalp, int cmd)
589 register struct usal_cmd *scmd = usalp->scmd;
591 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
592 scmd->addr = (caddr_t)0;
594 scmd->flags = SCG_DISRE_ENA;
595 scmd->cdb_len = SC_G0_CDBLEN;
596 scmd->sense_len = DEF_SENSE_LEN;
597 scmd->cdb.g0_cdb.cmd = 0x0D; /* qic02 Sysgen SC4000 */
598 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
599 scmd->cdb.g0_cdb.mid_addr = cmd;
601 usalp->cmdname = "qic 02";
602 return (usal_cmd(usalp));
605 #define G0_MAXADDR 0x1FFFFFL
608 write_xscsi(SCSI *usalp, caddr_t bp, long addr, long size, int cnt)
610 if (addr <= G0_MAXADDR)
611 return (write_xg0(usalp, bp, addr, size, cnt));
613 return (write_xg1(usalp, bp, addr, size, cnt));
617 write_xg0(SCSI *usalp,
618 caddr_t bp /* address of buffer */,
619 long addr /* disk address (sector) to put */,
620 long size /* number of bytes to transfer */,
621 int cnt /* sectorcount */)
623 register struct usal_cmd *scmd = usalp->scmd;
625 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
628 scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
629 /* scmd->flags = SCG_DISRE_ENA;*/
630 scmd->cdb_len = SC_G0_CDBLEN;
631 scmd->sense_len = CCS_SENSE_LEN;
632 scmd->cdb.g0_cdb.cmd = SC_WRITE;
633 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
634 g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
635 scmd->cdb.g0_cdb.count = cnt;
637 usalp->cmdname = "write_g0";
639 if (usal_cmd(usalp) < 0)
641 return (size - usal_getresid(usalp));
645 write_xg1(SCSI *usalp,
646 caddr_t bp /* address of buffer */,
647 long addr /* disk address (sector) to put */,
648 long size /* number of bytes to transfer */,
649 int cnt /* sectorcount */)
651 register struct usal_cmd *scmd = usalp->scmd;
653 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
656 scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
657 /* scmd->flags = SCG_DISRE_ENA;*/
658 scmd->cdb_len = SC_G1_CDBLEN;
659 scmd->sense_len = CCS_SENSE_LEN;
660 scmd->cdb.g1_cdb.cmd = SC_EWRITE;
661 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
662 g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
663 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
665 usalp->cmdname = "write_g1";
667 if (usal_cmd(usalp) < 0)
669 return (size - usal_getresid(usalp));
673 write_xg5(SCSI *usalp,
674 caddr_t bp /* address of buffer */,
675 long addr /* disk address (sector) to put */,
676 long size /* number of bytes to transfer */,
677 int cnt /* sectorcount */)
679 register struct usal_cmd *scmd = usalp->scmd;
681 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
684 scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
685 /* scmd->flags = SCG_DISRE_ENA;*/
686 scmd->cdb_len = SC_G5_CDBLEN;
687 scmd->sense_len = CCS_SENSE_LEN;
688 scmd->cdb.g5_cdb.cmd = 0xAA;
689 scmd->cdb.g5_cdb.lun = usal_lun(usalp);
690 g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
691 g5_cdblen(&scmd->cdb.g5_cdb, cnt);
693 usalp->cmdname = "write_g5";
695 if (usal_cmd(usalp) < 0)
697 return (size - usal_getresid(usalp));
701 seek_scsi(SCSI *usalp, long addr)
703 if (addr <= G0_MAXADDR)
704 return (seek_g0(usalp, addr));
706 return (seek_g1(usalp, addr));
710 seek_g0(SCSI *usalp, long addr)
712 register struct usal_cmd *scmd = usalp->scmd;
714 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
715 scmd->flags = SCG_DISRE_ENA;
716 scmd->cdb_len = SC_G0_CDBLEN;
717 scmd->sense_len = CCS_SENSE_LEN;
718 scmd->cdb.g0_cdb.cmd = 0x0B; /* Seek */
719 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
720 g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
722 usalp->cmdname = "seek_g0";
724 return (usal_cmd(usalp));
728 seek_g1(SCSI *usalp, long addr)
730 register struct usal_cmd *scmd = usalp->scmd;
732 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
733 scmd->flags = SCG_DISRE_ENA;
734 scmd->cdb_len = SC_G1_CDBLEN;
735 scmd->sense_len = CCS_SENSE_LEN;
736 scmd->cdb.g1_cdb.cmd = 0x2B; /* Seek G1 */
737 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
738 g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
740 usalp->cmdname = "seek_g1";
742 return (usal_cmd(usalp));
746 scsi_flush_cache(SCSI *usalp, BOOL immed)
748 register struct usal_cmd *scmd = usalp->scmd;
750 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
751 scmd->flags = SCG_DISRE_ENA;
752 scmd->cdb_len = SC_G1_CDBLEN;
753 scmd->sense_len = CCS_SENSE_LEN;
754 scmd->timeout = 2 * 60; /* Max: sizeof (CDR-cache)/150KB/s */
755 scmd->cdb.g1_cdb.cmd = 0x35;
756 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
759 scmd->cdb.cmd_cdb[1] |= 0x02;
761 usalp->cmdname = "flush cache";
763 if (usal_cmd(usalp) < 0)
769 read_buffer(SCSI *usalp, caddr_t bp, int cnt, int mode)
771 register struct usal_cmd *scmd = usalp->scmd;
773 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
777 scmd->cdb_len = SC_G1_CDBLEN;
778 scmd->sense_len = CCS_SENSE_LEN;
779 scmd->cdb.g1_cdb.cmd = 0x3C; /* Read Buffer */
780 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
781 scmd->cdb.cmd_cdb[1] |= (mode & 7);
782 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
784 usalp->cmdname = "read buffer";
786 return (usal_cmd(usalp));
790 write_buffer(SCSI *usalp, char *buffer, long length, int mode, int bufferid,
793 register struct usal_cmd *scmd = usalp->scmd;
796 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
799 scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
800 scmd->cdb_len = SC_G1_CDBLEN;
801 scmd->sense_len = CCS_SENSE_LEN;
803 cdb = (char *)scmd->cdb.cmd_cdb;
808 cdb[3] = offset >> 16;
809 cdb[4] = (offset >> 8) & 0xff;
810 cdb[5] = offset & 0xff;
811 cdb[6] = length >> 16;
812 cdb[7] = (length >> 8) & 0xff;
813 cdb[8] = length & 0xff;
815 usalp->cmdname = "write_buffer";
817 if (usal_cmd(usalp) >= 0)
823 read_subchannel(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int subq,
827 register struct usal_cmd *scmd = usalp->scmd;
829 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
832 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
833 scmd->cdb_len = SC_G1_CDBLEN;
834 scmd->sense_len = CCS_SENSE_LEN;
835 scmd->cdb.g1_cdb.cmd = 0x42;
836 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
838 scmd->cdb.g1_cdb.res = 1;
840 scmd->cdb.g1_cdb.addr[0] = 0x40;
841 scmd->cdb.g1_cdb.addr[1] = fmt;
842 scmd->cdb.g1_cdb.res6 = track;
843 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
845 usalp->cmdname = "read subchannel";
847 if (usal_cmd(usalp) < 0)
853 read_toc(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int fmt)
855 register struct usal_cmd *scmd = usalp->scmd;
857 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
860 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
861 scmd->cdb_len = SC_G1_CDBLEN;
862 scmd->sense_len = CCS_SENSE_LEN;
863 scmd->cdb.g1_cdb.cmd = 0x43;
864 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
866 scmd->cdb.g1_cdb.res = 1;
867 scmd->cdb.g1_cdb.addr[0] = fmt & 0x0F;
868 scmd->cdb.g1_cdb.res6 = track;
869 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
871 usalp->cmdname = "read toc";
873 if (usal_cmd(usalp) < 0)
879 read_toc_philips(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int fmt)
881 register struct usal_cmd *scmd = usalp->scmd;
883 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
886 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
887 scmd->cdb_len = SC_G1_CDBLEN;
888 scmd->sense_len = CCS_SENSE_LEN;
889 scmd->timeout = 4 * 60; /* May last 174s on a TEAC CD-R55S */
890 scmd->cdb.g1_cdb.cmd = 0x43;
891 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
893 scmd->cdb.g1_cdb.res = 1;
894 scmd->cdb.g1_cdb.res6 = track;
895 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
898 scmd->cdb.g1_cdb.vu_96 = 1;
900 scmd->cdb.g1_cdb.vu_97 = 1;
902 usalp->cmdname = "read toc";
904 if (usal_cmd(usalp) < 0)
910 read_header(SCSI *usalp, caddr_t bp, long addr, int cnt, int msf)
912 register struct usal_cmd *scmd = usalp->scmd;
914 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
917 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
918 scmd->cdb_len = SC_G1_CDBLEN;
919 scmd->sense_len = CCS_SENSE_LEN;
920 scmd->cdb.g1_cdb.cmd = 0x44;
921 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
923 scmd->cdb.g1_cdb.res = 1;
924 g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
925 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
927 usalp->cmdname = "read header";
929 if (usal_cmd(usalp) < 0)
935 read_disk_info(SCSI *usalp, caddr_t bp, int cnt)
937 register struct usal_cmd *scmd = usalp->scmd;
939 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
942 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
943 scmd->cdb_len = SC_G1_CDBLEN;
944 scmd->sense_len = CCS_SENSE_LEN;
945 scmd->timeout = 4 * 60; /* Needs up to 2 minutes */
946 scmd->cdb.g1_cdb.cmd = 0x51;
947 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
948 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
950 usalp->cmdname = "read disk info";
952 if (usal_cmd(usalp) < 0)
958 read_track_info(SCSI *usalp, caddr_t bp, int type, int addr, int cnt)
960 register struct usal_cmd *scmd = usalp->scmd;
962 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
965 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
966 scmd->cdb_len = SC_G1_CDBLEN;
967 scmd->sense_len = CCS_SENSE_LEN;
968 scmd->timeout = 4 * 60; /* Needs up to 2 minutes */
969 scmd->cdb.g1_cdb.cmd = 0x52;
970 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
971 /* scmd->cdb.cmd_cdb[1] = type & 0x03;*/
972 scmd->cdb.cmd_cdb[1] = type;
973 g1_cdbaddr(&scmd->cdb.g1_cdb, addr); /* LBA/Track/Session */
974 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
976 usalp->cmdname = "read track info";
978 if (usal_cmd(usalp) < 0)
984 reserve_track(SCSI *usalp, Ulong size)
986 register struct usal_cmd *scmd = usalp->scmd;
988 fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
989 scmd->flags = SCG_DISRE_ENA;
990 scmd->cdb_len = SC_G1_CDBLEN;
991 scmd->sense_len = CCS_SENSE_LEN;
992 scmd->cdb.g1_cdb.cmd = 0x53;
993 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
994 i_to_4_byte(&scmd->cdb.g1_cdb.addr[3], size);
996 usalp->cmdname = "reserve track";
998 if (usal_cmd(usalp) < 0)
1006 read_rzone_info(SCSI *usalp, caddr_t bp, int cnt)
1008 return (read_track_info(usalp, bp, TI_TYPE_LBA, 0, cnt));
1012 reserve_tr_rzone(SCSI *usalp, long size /* number of blocks */)
1014 register struct usal_cmd *scmd = usalp->scmd;
1016 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1017 scmd->addr = (caddr_t)0;
1019 scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
1020 scmd->cdb_len = SC_G1_CDBLEN;
1021 scmd->sense_len = CCS_SENSE_LEN;
1022 scmd->cdb.g1_cdb.cmd = 0x53;
1023 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1025 i_to_4_byte(&scmd->cdb.g1_cdb.addr[3], size);
1027 usalp->cmdname = "reserve_track_rzone";
1029 if (usal_cmd(usalp) < 0)
1035 read_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int addr, int layer,
1038 register struct usal_cmd *scmd = usalp->scmd;
1040 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1043 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1044 scmd->cdb_len = SC_G5_CDBLEN;
1045 scmd->sense_len = CCS_SENSE_LEN;
1046 scmd->timeout = 4 * 60; /* Needs up to 2 minutes ??? */
1047 scmd->cdb.g5_cdb.cmd = 0xAD;
1048 scmd->cdb.g5_cdb.lun = usal_lun(usalp);
1049 g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
1050 g5_cdblen(&scmd->cdb.g5_cdb, cnt);
1051 scmd->cdb.g5_cdb.count[0] = layer;
1052 scmd->cdb.g5_cdb.count[1] = fmt;
1054 usalp->cmdname = "read dvd structure";
1056 if (usal_cmd(usalp) < 0)
1062 send_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int layer, int fmt)
1064 register struct usal_cmd *scmd = usalp->scmd;
1066 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1069 scmd->flags = SCG_DISRE_ENA;
1070 scmd->cdb_len = SC_G5_CDBLEN;
1071 scmd->sense_len = CCS_SENSE_LEN;
1072 scmd->timeout = 4 * 60; /* Needs up to 2 minutes ??? */
1073 scmd->cdb.g5_cdb.cmd = 0xBF;
1074 scmd->cdb.g5_cdb.lun = usal_lun(usalp);
1075 g5_cdblen(&scmd->cdb.g5_cdb, cnt);
1077 scmd->cdb.cmd_cdb[7] = fmt;
1079 usalp->cmdname = "send dvd structure";
1081 if (usal_cmd(usalp) < 0)
1087 send_opc(SCSI *usalp, caddr_t bp, int cnt, int doopc)
1089 register struct usal_cmd *scmd = usalp->scmd;
1091 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1094 scmd->flags = SCG_DISRE_ENA;
1095 scmd->cdb_len = SC_G1_CDBLEN;
1096 scmd->sense_len = CCS_SENSE_LEN;
1098 scmd->cdb.g1_cdb.cmd = 0x54;
1099 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1100 scmd->cdb.g1_cdb.reladr = doopc?1:0;
1101 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1103 usalp->cmdname = "send opc";
1105 if (usal_cmd(usalp) < 0)
1111 read_track_info_philips(SCSI *usalp, caddr_t bp, int track, int cnt)
1113 register struct usal_cmd *scmd = usalp->scmd;
1115 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1118 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1119 scmd->cdb_len = SC_G1_CDBLEN;
1120 scmd->sense_len = CCS_SENSE_LEN;
1121 scmd->cdb.g1_cdb.cmd = 0xE5;
1122 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1123 g1_cdbaddr(&scmd->cdb.g1_cdb, track);
1124 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1126 usalp->cmdname = "read track info";
1128 if (usal_cmd(usalp) < 0)
1134 scsi_close_tr_session(SCSI *usalp, int type, int track, BOOL immed)
1136 register struct usal_cmd *scmd = usalp->scmd;
1138 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1139 scmd->flags = SCG_DISRE_ENA;
1140 scmd->cdb_len = SC_G1_CDBLEN;
1141 scmd->sense_len = CCS_SENSE_LEN;
1142 scmd->timeout = 8 * 60; /* Needs up to 4 minutes */
1143 scmd->cdb.g1_cdb.cmd = 0x5B;
1144 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1145 scmd->cdb.g1_cdb.addr[0] = type;
1146 scmd->cdb.g1_cdb.addr[3] = track;
1149 scmd->cdb.g1_cdb.reladr = 1;
1150 /* scmd->cdb.cmd_cdb[1] |= 0x01;*/
1152 scmd->cdb.g1_cdb.reladr = 1; /* IMM hack to test Mitsumi behaviour*/
1155 usalp->cmdname = "close track/session";
1157 if (usal_cmd(usalp) < 0)
1163 read_master_cue(SCSI *usalp, caddr_t bp, int sheet, int cnt)
1165 register struct usal_cmd *scmd = usalp->scmd;
1167 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1170 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1171 scmd->cdb_len = SC_G1_CDBLEN;
1172 scmd->sense_len = CCS_SENSE_LEN;
1173 scmd->cdb.g1_cdb.cmd = 0x59; /* Read master cue */
1174 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1175 scmd->cdb.g1_cdb.addr[2] = sheet;
1176 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1178 usalp->cmdname = "read master cue";
1180 if (usal_cmd(usalp) < 0)
1186 send_cue_sheet(SCSI *usalp, caddr_t bp, long size)
1188 register struct usal_cmd *scmd = usalp->scmd;
1190 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1193 scmd->flags = SCG_DISRE_ENA;
1194 scmd->cdb_len = SC_G1_CDBLEN;
1195 scmd->sense_len = CCS_SENSE_LEN;
1196 scmd->cdb.g1_cdb.cmd = 0x5D; /* Send CUE sheet */
1197 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1198 g1_cdblen(&scmd->cdb.g1_cdb, size);
1200 usalp->cmdname = "send_cue_sheet";
1202 if (usal_cmd(usalp) < 0)
1204 return (size - scmd->resid);
1208 read_buff_cap(SCSI *usalp, long *sp, long *fp)
1214 register struct usal_cmd *scmd = usalp->scmd;
1216 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1217 scmd->addr = (caddr_t)resp;
1218 scmd->size = sizeof (resp);
1219 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1220 scmd->cdb_len = SC_G1_CDBLEN;
1221 scmd->sense_len = CCS_SENSE_LEN;
1222 scmd->cdb.g1_cdb.cmd = 0x5C; /* Read buffer cap */
1223 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1224 g1_cdblen(&scmd->cdb.g1_cdb, sizeof (resp));
1226 usalp->cmdname = "read buffer cap";
1228 if (usal_cmd(usalp) < 0)
1231 bufsize = a_to_u_4_byte(&resp[4]);
1232 freespace = a_to_u_4_byte(&resp[8]);
1238 if (usalp->verbose || (sp == 0 && fp == 0))
1239 printf("BFree: %ld K BSize: %ld K\n", freespace >> 10, bufsize >> 10);
1243 per = (100 * (bufsize - freespace)) / bufsize;
1252 scsi_blank(SCSI *usalp, long addr, int blanktype, BOOL immed)
1254 register struct usal_cmd *scmd = usalp->scmd;
1256 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1257 scmd->flags = SCG_DISRE_ENA;
1258 scmd->cdb_len = SC_G5_CDBLEN;
1259 scmd->sense_len = CCS_SENSE_LEN;
1260 scmd->timeout = 160 * 60; /* full blank at 1x could take 80 minutes */
1261 scmd->cdb.g5_cdb.cmd = 0xA1; /* Blank */
1262 scmd->cdb.g0_cdb.high_addr = blanktype;
1263 g1_cdbaddr(&scmd->cdb.g5_cdb, addr);
1266 scmd->cdb.g5_cdb.res |= 8;
1267 /* scmd->cdb.cmd_cdb[1] |= 0x10;*/
1269 usalp->cmdname = "blank unit";
1271 return (usal_cmd(usalp));
1275 scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background)
1277 register struct usal_cmd *scmd = usalp->scmd;
1278 int progress=0, ret=-1, pid=-1;
1279 unsigned char sense_table[18];
1282 printf("scsi_format: preparing\n");
1284 fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
1287 scmd->flags = SCG_DISRE_ENA;
1288 scmd->cdb_len = SC_G5_CDBLEN;
1289 scmd->sense_len = CCS_SENSE_LEN;
1290 scmd->timeout = 160 * 60; /* Do not know what to set */
1291 scmd->cdb.g5_cdb.cmd = 0x04; /* Format Unit */
1292 scmd->cdb.cmd_cdb[1] = 0x11; /* "FmtData" and "Format Code" */
1293 scmd->cdb.cmd_cdb[5] = 0;
1295 usalp->cmdname = "format unit";
1297 printf("scsi_format: running\n");
1298 ret = (usal_cmd(usalp));
1299 printf("scsi_format: post processing %d\n", ret);
1300 if (ret == -1) return ret;
1302 if ((pid=fork()) == (pid_t)-1)
1303 perror ("- [unable to fork()]");
1307 if (test_unit_ready(usalp) >= 0)
1315 printf("Formating in progress: 0.00 %% done.");
1318 while (progress < 0xfff0 && !(progress == 0 && i > 50)) {
1319 test_unit_ready(usalp);
1320 request_sense_b(usalp, (caddr_t)sense_table, 18);
1321 progress = sense_table[16]<<8|sense_table[17];
1322 printf("\rFormating in progress: %.2f %% done [%d]. ", (float)(progress*100)/0x10000,progress);
1325 /*for (i=0; i < 18; i++) {
1326 printf("%d ", sense_table[i]);
1330 printf("\rFormating in progress: 100.00 %% done. \n");
1336 * XXX First try to handle ATAPI:
1337 * XXX ATAPI cannot handle SCSI 6 byte commands.
1338 * XXX We try to simulate 6 byte mode sense/select.
1340 static BOOL is_atapi;
1343 allow_atapi(SCSI *usalp, BOOL new)
1345 BOOL old = is_atapi;
1353 * If a bad drive has been reset before, we may need to fire up two
1354 * test unit ready commands to clear status.
1356 (void) unit_ready(usalp);
1358 mode_sense_g1(usalp, mode, 8, 0x3F, 0) < 0) { /* All pages current */
1368 mode_select(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1371 return (mode_select_sg0(usalp, dp, cnt, smp, pf));
1372 return (mode_select_g0(usalp, dp, cnt, smp, pf));
1376 mode_sense(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1379 return (mode_sense_sg0(usalp, dp, cnt, page, pcf));
1380 return (mode_sense_g0(usalp, dp, cnt, page, pcf));
1384 * Simulate mode select g0 with mode select g1.
1387 mode_select_sg0(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1392 if (amt < 1 || amt > 255) {
1393 /* XXX clear SCSI error codes ??? */
1397 if (amt < 4) { /* Data length. medium type & VU */
1401 movebytes(&dp[4], &xmode[8], cnt-4);
1409 i_to_2_byte(&xmode[6], (unsigned int)dp[3]);
1411 if (usalp->verbose) usal_prbytes("Mode Parameters (un-converted)", dp, cnt);
1413 return (mode_select_g1(usalp, xmode, amt, smp, pf));
1417 * Simulate mode sense g0 with mode sense g1.
1420 mode_sense_sg0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1426 if (amt < 1 || amt > 255) {
1427 /* XXX clear SCSI error codes ??? */
1431 fillbytes((caddr_t)xmode, sizeof (xmode), '\0');
1432 if (amt < 4) { /* Data length. medium type & VU */
1437 if (mode_sense_g1(usalp, xmode, amt, page, pcf) < 0)
1440 amt = cnt - usal_getresid(usalp);
1442 * For tests: Solaris 8 & LG CD-ROM always returns resid == amt
1446 movebytes(&xmode[8], &dp[4], amt-4);
1447 len = a_to_u_2_byte(xmode);
1450 } else if (len < 6) {
1459 len = a_to_u_2_byte(&xmode[6]);
1462 if (usalp->verbose) usal_prbytes("Mode Sense Data (converted)", dp, amt);
1467 mode_select_g0(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1469 register struct usal_cmd *scmd = usalp->scmd;
1471 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1472 scmd->addr = (caddr_t)dp;
1474 scmd->flags = SCG_DISRE_ENA;
1475 scmd->cdb_len = SC_G0_CDBLEN;
1476 scmd->sense_len = CCS_SENSE_LEN;
1477 scmd->cdb.g0_cdb.cmd = SC_MODE_SELECT;
1478 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
1479 scmd->cdb.g0_cdb.high_addr = smp ? 1 : 0 | pf ? 0x10 : 0;
1480 scmd->cdb.g0_cdb.count = cnt;
1482 if (usalp->verbose) {
1483 fprintf(stderr, "%s ", smp?"Save":"Set ");
1484 usal_prbytes("Mode Parameters", dp, cnt);
1487 usalp->cmdname = "mode select g0";
1489 return (usal_cmd(usalp));
1493 mode_select_g1(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1495 register struct usal_cmd *scmd = usalp->scmd;
1497 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1498 scmd->addr = (caddr_t)dp;
1500 scmd->flags = SCG_DISRE_ENA;
1501 scmd->cdb_len = SC_G1_CDBLEN;
1502 scmd->sense_len = CCS_SENSE_LEN;
1503 scmd->cdb.g1_cdb.cmd = 0x55;
1504 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1505 scmd->cdb.g0_cdb.high_addr = smp ? 1 : 0 | pf ? 0x10 : 0;
1506 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1508 if (usalp->verbose) {
1509 printf("%s ", smp?"Save":"Set ");
1510 usal_prbytes("Mode Parameters", dp, cnt);
1513 usalp->cmdname = "mode select g1";
1515 return (usal_cmd(usalp));
1519 mode_sense_g0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1521 register struct usal_cmd *scmd = usalp->scmd;
1523 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1524 scmd->addr = (caddr_t)dp;
1527 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1528 scmd->cdb_len = SC_G0_CDBLEN;
1529 scmd->sense_len = CCS_SENSE_LEN;
1530 scmd->cdb.g0_cdb.cmd = SC_MODE_SENSE;
1531 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
1533 scmd->cdb.g0_cdb.high_addr = 1<<4; /* DBD Disable Block desc. */
1535 scmd->cdb.g0_cdb.mid_addr = (page&0x3F) | ((pcf<<6)&0xC0);
1536 scmd->cdb.g0_cdb.count = page ? 0xFF : 24;
1537 scmd->cdb.g0_cdb.count = cnt;
1539 usalp->cmdname = "mode sense g0";
1541 if (usal_cmd(usalp) < 0)
1543 if (usalp->verbose) usal_prbytes("Mode Sense Data", dp, cnt - usal_getresid(usalp));
1548 mode_sense_g1(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1550 register struct usal_cmd *scmd = usalp->scmd;
1552 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1553 scmd->addr = (caddr_t)dp;
1555 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
1556 scmd->cdb_len = SC_G1_CDBLEN;
1557 scmd->sense_len = CCS_SENSE_LEN;
1558 scmd->cdb.g1_cdb.cmd = 0x5A;
1559 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
1561 scmd->cdb.g0_cdb.high_addr = 1<<4; /* DBD Disable Block desc. */
1563 scmd->cdb.g1_cdb.addr[0] = (page&0x3F) | ((pcf<<6)&0xC0);
1564 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1566 usalp->cmdname = "mode sense g1";
1568 if (usal_cmd(usalp) < 0)
1570 if (usalp->verbose) usal_prbytes("Mode Sense Data", dp, cnt - usal_getresid(usalp));
1577 #if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
1580 #else /* Motorola byteorder */
1591 struct tocheader hd;
1592 struct trackdesc desc[1];
1611 struct sidesc desc[1];
1614 struct trackheader {
1620 #define TRM_USER_ECC 1 /* 2048 bytes user data + 288 Bytes ECC/EDC */
1621 #define TRM_USER 2 /* All user data (2336 bytes) */
1625 read_tochdr(SCSI *usalp, cdr_t *dp, int *fp, int *lp)
1627 struct tocheader *tp;
1631 tp = (struct tocheader *)xb;
1633 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1634 if (read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_TOC) < 0) {
1635 if (usalp->silent == 0)
1636 errmsgno(EX_BAD, "Cannot read TOC header\n");
1639 len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
1651 read_cdtext(SCSI *usalp)
1653 struct tocheader *tp;
1658 tp = (struct tocheader *)xb;
1660 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1661 if (read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_CDTEXT) < 0) {
1662 if (usalp->silent == 0 || usalp->verbose > 0)
1663 errmsgno(EX_BAD, "Cannot read CD-Text header\n");
1666 len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
1667 printf("CD-Text len: %d\n", len);
1669 if (read_toc(usalp, xxb, 0, len, 0, FMT_CDTEXT) < 0) {
1670 if (usalp->silent == 0)
1671 errmsgno(EX_BAD, "Cannot read CD-Text\n");
1675 FILE *f = fileopen("cdtext.dat", "wctb");
1676 filewrite(f, xxb, len);
1682 read_trackinfo(SCSI *usalp, int track, long *offp, struct msf *msfp, int *adrp,
1683 int *controlp, int *modep)
1685 struct diskinfo *dp;
1689 dp = (struct diskinfo *)xb;
1691 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1692 if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 0, FMT_TOC) < 0) {
1693 if (usalp->silent <= 0)
1694 errmsgno(EX_BAD, "Cannot read TOC\n");
1697 len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
1698 if (len < (int)sizeof (struct diskinfo))
1702 *offp = a_to_4_byte(dp->desc[0].addr);
1704 *adrp = dp->desc[0].adr;
1706 *controlp = dp->desc[0].control;
1710 if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 1, FMT_TOC)
1712 msfp->msf_min = dp->desc[0].addr[1];
1713 msfp->msf_sec = dp->desc[0].addr[2];
1714 msfp->msf_frame = dp->desc[0].addr[3];
1715 } else if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 0, FMT_TOC)
1718 * Some drives (e.g. the Philips CDD-522) don't support
1719 * to read the TOC in MSF mode.
1721 long off = a_to_4_byte(dp->desc[0].addr);
1723 lba_to_msf(off, msfp);
1727 msfp->msf_frame = 0;
1735 if (track == 0xAA) {
1740 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1743 if (read_header(usalp, xb, *offp, 8, 0) >= 0) {
1745 } else if (read_track_info_philips(usalp, xb, track, 14) >= 0) {
1746 *modep = xb[0xb] & 0xF;
1755 read_B0(SCSI *usalp, BOOL isbcd, long *b0p, long *lop)
1757 struct fdiskinfo *dp;
1758 struct ftrackdesc *tp;
1764 dp = (struct fdiskinfo *)xb;
1766 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1767 if (read_toc_philips(usalp, xb, 1, sizeof (struct tocheader), 0, FMT_FULLTOC) < 0) {
1770 len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
1771 if (len < (int)sizeof (struct fdiskinfo))
1773 if (read_toc_philips(usalp, xb, 1, len, 0, FMT_FULLTOC) < 0) {
1776 if (usalp->verbose) {
1777 usal_prbytes("TOC data: ", (Uchar *)xb,
1778 len > (int)sizeof (xb) - usal_getresid(usalp) ?
1779 sizeof (xb) - usal_getresid(usalp) : len);
1784 while ((char *)tp < pe) {
1785 usal_prbytes("ENT: ", (Uchar *)tp, 11);
1792 for (; (char *)tp < pe; tp++) {
1793 if (tp->sess_number != dp->hd.last)
1795 if (tp->point != 0xB0)
1798 usal_prbytes("B0: ", (Uchar *)tp, 11);
1800 l = msf_to_lba(from_bcd(tp->amin),
1802 from_bcd(tp->aframe), TRUE);
1804 l = msf_to_lba(tp->amin,
1812 printf("B0 start: %ld\n", l);
1815 l = msf_to_lba(from_bcd(tp->pmin),
1817 from_bcd(tp->pframe), TRUE);
1819 l = msf_to_lba(tp->pmin,
1825 printf("B0 lout: %ld\n", l);
1835 * Return address of first track in last session (SCSI-3/mmc version).
1838 read_session_offset(SCSI *usalp, long *offp)
1840 struct diskinfo *dp;
1844 dp = (struct diskinfo *)xb;
1846 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1847 if (read_toc(usalp, (caddr_t)xb, 0, sizeof (struct tocheader), 0, FMT_SINFO) < 0)
1851 usal_prbytes("tocheader: ",
1852 (Uchar *)xb, sizeof (struct tocheader) - usal_getresid(usalp));
1854 len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
1855 if (len > (int)sizeof (xb)) {
1856 errmsgno(EX_BAD, "Session info too big.\n");
1859 if (read_toc(usalp, (caddr_t)xb, 0, len, 0, FMT_SINFO) < 0)
1863 usal_prbytes("tocheader: ",
1864 (Uchar *)xb, len - usal_getresid(usalp));
1866 dp = (struct diskinfo *)xb;
1868 *offp = a_to_u_4_byte(dp->desc[0].addr);
1873 * Return address of first track in last session (pre SCSI-3 version).
1876 read_session_offset_philips(SCSI *usalp, long *offp)
1882 sp = (struct sinfo *)xb;
1884 fillbytes((caddr_t)xb, sizeof (xb), '\0');
1885 if (read_toc_philips(usalp, (caddr_t)xb, 0, sizeof (struct siheader), 0, FMT_SINFO) < 0)
1887 len = a_to_u_2_byte(sp->hd.len) + sizeof (struct siheader)-2;
1888 if (len > (int)sizeof (xb)) {
1889 errmsgno(EX_BAD, "Session info too big.\n");
1892 if (read_toc_philips(usalp, (caddr_t)xb, 0, len, 0, FMT_SINFO) < 0)
1895 * Old drives return the number of finished sessions in first/finished
1896 * a descriptor is returned for each session.
1897 * New drives return the number of the first and last session
1898 * one descriptor for the last finished session is returned
1900 * In all cases the lowest session number is set to 1.
1902 sp = (struct sinfo *)xb;
1904 *offp = a_to_u_4_byte(sp->desc[sp->hd.finished-1].addr);
1909 sense_secsize(SCSI *usalp, int current)
1918 (void) unit_ready(usalp);
1921 /* XXX Quick and dirty, musz verallgemeinert werden !!! */
1923 fillbytes(mode, sizeof (mode), '\0');
1926 len = sizeof (struct scsi_mode_header) +
1927 sizeof (struct scsi_mode_blockdesc);
1929 * Wenn wir hier get_mode_params() nehmen bekommen wir die Warnung:
1930 * Warning: controller returns wrong page 1 for All pages page (3F).
1932 if (mode_sense(usalp, mode, len, 0x3F, current?0:2) < 0) {
1933 fillbytes(mode, sizeof (mode), '\0');
1934 if (mode_sense(usalp, mode, len, 0, current?0:2) < 0) { /* VU (block desc) */
1941 printf("Density: 0x%X\n", mode[4]);
1942 printf("Blocks: %ld\n", a_to_u_3_byte(&mode[5]));
1943 printf("Blocklen:%ld\n", a_to_u_3_byte(&mode[9]));
1945 secsize = a_to_u_3_byte(&mode[9]);
1947 fillbytes(mode, sizeof (mode), '\0');
1949 * The ACARD TECH AEC-7720 ATAPI<->SCSI adaptor
1950 * chokes if we try to transfer more than 0x40 bytes with
1951 * mode_sense of all pages. So try to avoid to run this
1952 * command if possible.
1955 mode_sense(usalp, mode, 0xFE, 0x3F, current?0:2) >= 0) { /* All Pages */
1957 ep = mode+mode[0]; /* Points to last byte of data */
1962 printf("0x%X ", *p&0x3F);
1973 select_secsize(SCSI *usalp, int secsize)
1975 struct scsi_mode_data md;
1976 int count = sizeof (struct scsi_mode_header) +
1977 sizeof (struct scsi_mode_blockdesc);
1979 (void) test_unit_ready(usalp); /* clear any error situation */
1981 fillbytes((caddr_t)&md, sizeof (md), '\0');
1982 md.header.blockdesc_len = 8;
1983 i_to_3_byte(md.blockdesc.lblen, secsize);
1985 return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
1989 is_cddrive(SCSI *usalp)
1991 return (usalp->inq->type == INQ_ROMD || usalp->inq->type == INQ_WORM);
1995 is_unknown_dev(SCSI *usalp)
1997 return (usalp->dev == DEV_UNKNOWN);
2006 read_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt)
2008 if (addr <= G0_MAXADDR && cnt < 256 && !is_atapi)
2009 return (read_g0(usalp, bp, addr, cnt));
2011 return (read_g1(usalp, bp, addr, cnt));
2015 read_g0(SCSI *usalp, caddr_t bp, long addr, int cnt)
2017 register struct usal_cmd *scmd = usalp->scmd;
2019 if (usalp->cap->c_bsize <= 0)
2020 raisecond("capacity_not_set", 0L);
2022 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2024 scmd->size = cnt*usalp->cap->c_bsize;
2025 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2026 scmd->cdb_len = SC_G0_CDBLEN;
2027 scmd->sense_len = CCS_SENSE_LEN;
2028 scmd->cdb.g0_cdb.cmd = SC_READ;
2029 scmd->cdb.g0_cdb.lun = usal_lun(usalp);
2030 g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
2031 scmd->cdb.g0_cdb.count = cnt;
2032 /* scmd->cdb.g0_cdb.vu_56 = 1;*/
2034 usalp->cmdname = "read_g0";
2036 return (usal_cmd(usalp));
2040 read_g1(SCSI *usalp, caddr_t bp, long addr, int cnt)
2042 register struct usal_cmd *scmd = usalp->scmd;
2044 if (usalp->cap->c_bsize <= 0)
2045 raisecond("capacity_not_set", 0L);
2047 fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2049 scmd->size = cnt*usalp->cap->c_bsize;
2050 scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
2051 scmd->cdb_len = SC_G1_CDBLEN;
2052 scmd->sense_len = CCS_SENSE_LEN;
2053 scmd->cdb.g1_cdb.cmd = SC_EREAD;
2054 scmd->cdb.g1_cdb.lun = usal_lun(usalp);
2055 g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
2056 g1_cdblen(&scmd->cdb.g1_cdb, cnt);
2058 usalp->cmdname = "read_g1";
2060 return (usal_cmd(usalp));
2065 getdev(SCSI *usalp, BOOL print)
2067 BOOL got_inquiry = TRUE;
2068 char vendor_info[8+1];
2069 char prod_ident[16+1];
2070 char prod_revision[4+1];
2072 register struct usal_cmd *scmd = usalp->scmd;
2073 register struct scsi_inquiry *inq = usalp->inq;
2076 fillbytes((caddr_t)inq, sizeof (*inq), '\0');
2077 usalp->dev = DEV_UNKNOWN;
2079 (void) unit_ready(usalp);
2080 if (scmd->error >= SCG_FATAL &&
2081 !(scmd->scb.chk && scmd->sense_count > 0)) {
2087 /* if (scmd->error < SCG_FATAL || scmd->scb.chk && scmd->sense_count > 0){*/
2089 if (inquiry(usalp, (caddr_t)inq, sizeof (*inq)) < 0) {
2090 got_inquiry = FALSE;
2092 inq_len = sizeof (*inq) - usal_getresid(usalp);
2095 if (usalp->verbose) {
2097 "error: %d scb.chk: %d sense_count: %d sense.code: 0x%x\n",
2098 scmd->error, scmd->scb.chk,
2099 scmd->sense_count, scmd->sense.code);
2102 * Folgende Kontroller kennen das Kommando
2105 * ADAPTEC ACB-4000, ACB-4010, ACB 4070
2108 * Leider reagieren ACB40X0 und ACB5500 identisch
2109 * wenn drive not ready (code == not ready),
2110 * sie sind dann nicht zu unterscheiden.
2113 if (scmd->scb.chk && scmd->sense_count == 4) {
2114 /* Test auf SYSGEN */
2115 (void) qic02(usalp, 0x12); /* soft lock on */
2116 if (qic02(usalp, 1) < 0) { /* soft lock off */
2117 usalp->dev = DEV_ACB40X0;
2118 /* usalp->dev = acbdev();*/
2120 usalp->dev = DEV_SC4000;
2121 inq->type = INQ_SEQD;
2125 } else if (usalp->verbose) {
2127 int len = inq->add_len + 5;
2129 Uchar *ip = (Uchar *)inq;
2132 if (len > (int)sizeof (*inq) &&
2133 inquiry(usalp, (caddr_t)ibuf, inq->add_len+5) >= 0) {
2134 len = inq->add_len+5 - usal_getresid(usalp);
2137 len = sizeof (*inq);
2139 printf("Inquiry Data : ");
2140 for (i = 0; i < len; i++) {
2142 if (c >= ' ' && c < 0177)
2150 strncpy(vendor_info, inq->vendor_info, sizeof (inq->vendor_info));
2151 strncpy(prod_ident, inq->prod_ident, sizeof (inq->prod_ident));
2152 strncpy(prod_revision, inq->prod_revision, sizeof (inq->prod_revision));
2154 vendor_info[sizeof (inq->vendor_info)] = '\0';
2155 prod_ident[sizeof (inq->prod_ident)] = '\0';
2156 prod_revision[sizeof (inq->prod_revision)] = '\0';
2158 switch (inq->type) {
2161 if (inq->add_len == 0 && inq->vendor_info[0] != '\0') {
2164 * NT-4.0 creates fake inquiry data for IDE disks.
2165 * Unfortunately, it does not set add_len wo we
2166 * check if vendor_info, prod_ident and prod_revision
2167 * contains valid chars for a CCS inquiry.
2172 for (p = (Uchar *)&inq->vendor_info[0];
2173 p < (Uchar *)&inq->prod_revision[4];
2175 if (*p < 0x20 || *p > 0x7E) {
2181 if (inq->add_len == 0) {
2182 if (usalp->dev == DEV_UNKNOWN && got_inquiry) {
2183 usalp->dev = DEV_ACB5500;
2184 strcpy(inq->vendor_info,
2185 "ADAPTEC ACB-5500 FAKE");
2187 } else switch (usalp->dev) {
2190 strcpy(inq->vendor_info,
2191 "ADAPTEC ACB-40X0 FAKE");
2194 strcpy(inq->vendor_info,
2195 "ADAPTEC ACB-4000 FAKE");
2198 strcpy(inq->vendor_info,
2199 "ADAPTEC ACB-4010 FAKE");
2202 strcpy(inq->vendor_info,
2203 "ADAPTEC ACB-4070 FAKE");
2206 } else if (inq->add_len < 31) {
2207 usalp->dev = DEV_NON_CCS_DSK;
2209 } else if (strbeg("EMULEX", vendor_info)) {
2210 if (strbeg("MD21", prod_ident))
2211 usalp->dev = DEV_MD21;
2212 if (strbeg("MD23", prod_ident))
2213 usalp->dev = DEV_MD23;
2215 usalp->dev = DEV_CCS_GENDISK;
2216 } else if (strbeg("ADAPTEC", vendor_info)) {
2217 if (strbeg("ACB-4520", prod_ident))
2218 usalp->dev = DEV_ACB4520A;
2219 if (strbeg("ACB-4525", prod_ident))
2220 usalp->dev = DEV_ACB4525;
2222 usalp->dev = DEV_CCS_GENDISK;
2223 } else if (strbeg("SONY", vendor_info) &&
2224 strbeg("SMO-C501", prod_ident)) {
2225 usalp->dev = DEV_SONY_SMO;
2227 usalp->dev = DEV_CCS_GENDISK;
2232 if (usalp->dev == DEV_SC4000) {
2233 strcpy(inq->vendor_info,
2234 "SYSGEN SC4000 FAKE");
2235 } else if (inq->add_len == 0 &&
2237 inq->ansi_version == 1) {
2238 usalp->dev = DEV_MT02;
2239 strcpy(inq->vendor_info,
2240 "EMULEX MT02 FAKE");
2247 if (strbeg("RXT-800S", prod_ident))
2248 usalp->dev = DEV_RXT800S;
2251 * Start of CD-Recorders:
2253 if (strbeg("ACER", vendor_info)) {
2254 if (strbeg("CR-4020C", prod_ident))
2255 usalp->dev = DEV_RICOH_RO_1420C;
2257 } else if (strbeg("CREATIVE", vendor_info)) {
2258 if (strbeg("CDR2000", prod_ident))
2259 usalp->dev = DEV_RICOH_RO_1060C;
2261 } else if (strbeg("GRUNDIG", vendor_info)) {
2262 if (strbeg("CDR100IPW", prod_ident))
2263 usalp->dev = DEV_CDD_2000;
2265 } else if (strbeg("JVC", vendor_info)) {
2266 if (strbeg("XR-W2001", prod_ident))
2267 usalp->dev = DEV_TEAC_CD_R50S;
2268 else if (strbeg("XR-W2010", prod_ident))
2269 usalp->dev = DEV_TEAC_CD_R50S;
2270 else if (strbeg("R2626", prod_ident))
2271 usalp->dev = DEV_TEAC_CD_R50S;
2273 } else if (strbeg("MITSBISH", vendor_info)) {
2276 /* It's MMC compliant */
2277 if (strbeg("CDRW226", prod_ident))
2278 usalp->dev = DEV_MMC_CDRW;
2283 } else if (strbeg("MITSUMI", vendor_info)) {
2284 /* Don't know any product string */
2285 usalp->dev = DEV_CDD_522;
2287 } else if (strbeg("OPTIMA", vendor_info)) {
2288 if (strbeg("CD-R 650", prod_ident))
2289 usalp->dev = DEV_SONY_CDU_924;
2291 } else if (strbeg("PHILIPS", vendor_info) ||
2292 strbeg("IMS", vendor_info) ||
2293 strbeg("KODAK", vendor_info) ||
2294 strbeg("HP", vendor_info)) {
2296 if (strbeg("CDD521/00", prod_ident))
2297 usalp->dev = DEV_CDD_521_OLD;
2298 else if (strbeg("CDD521/02", prod_ident))
2299 usalp->dev = DEV_CDD_521_OLD; /* PCD 200R? */
2300 else if (strbeg("CDD521", prod_ident))
2301 usalp->dev = DEV_CDD_521;
2303 if (strbeg("CDD522", prod_ident))
2304 usalp->dev = DEV_CDD_522;
2305 if (strbeg("PCD225", prod_ident))
2306 usalp->dev = DEV_CDD_522;
2307 if (strbeg("KHSW/OB", prod_ident)) /* PCD600 */
2308 usalp->dev = DEV_PCD_600;
2309 if (strbeg("CDR-240", prod_ident))
2310 usalp->dev = DEV_CDD_2000;
2312 if (strbeg("CDD20", prod_ident))
2313 usalp->dev = DEV_CDD_2000;
2314 if (strbeg("CDD26", prod_ident))
2315 usalp->dev = DEV_CDD_2600;
2317 if (strbeg("C4324/C4325", prod_ident))
2318 usalp->dev = DEV_CDD_2000;
2319 if (strbeg("CD-Writer 6020", prod_ident))
2320 usalp->dev = DEV_CDD_2600;
2322 } else if (strbeg("PINNACLE", vendor_info)) {
2323 if (strbeg("RCD-1000", prod_ident))
2324 usalp->dev = DEV_TEAC_CD_R50S;
2325 if (strbeg("RCD5020", prod_ident))
2326 usalp->dev = DEV_TEAC_CD_R50S;
2327 if (strbeg("RCD5040", prod_ident))
2328 usalp->dev = DEV_TEAC_CD_R50S;
2329 if (strbeg("RCD 4X4", prod_ident))
2330 usalp->dev = DEV_TEAC_CD_R50S;
2332 } else if (strbeg("PIONEER", vendor_info)) {
2333 if (strbeg("CD-WO DW-S114X", prod_ident))
2334 usalp->dev = DEV_PIONEER_DW_S114X;
2335 else if (strbeg("CD-WO DR-R504X", prod_ident)) /* Reoprt from philip@merge.com */
2336 usalp->dev = DEV_PIONEER_DW_S114X;
2337 else if (strbeg("DVD-R DVR-S101", prod_ident))
2338 usalp->dev = DEV_PIONEER_DVDR_S101;
2340 } else if (strbeg("PLASMON", vendor_info)) {
2341 if (strbeg("RF4100", prod_ident))
2342 usalp->dev = DEV_PLASMON_RF_4100;
2343 else if (strbeg("CDR4220", prod_ident))
2344 usalp->dev = DEV_CDD_2000;
2346 } else if (strbeg("PLEXTOR", vendor_info)) {
2347 if (strbeg("CD-R PX-R24CS", prod_ident))
2348 usalp->dev = DEV_RICOH_RO_1420C;
2350 } else if (strbeg("RICOH", vendor_info)) {
2351 if (strbeg("RO-1420C", prod_ident))
2352 usalp->dev = DEV_RICOH_RO_1420C;
2353 if (strbeg("RO1060C", prod_ident))
2354 usalp->dev = DEV_RICOH_RO_1060C;
2356 } else if (strbeg("SAF", vendor_info)) { /* Smart & Friendly */
2357 if (strbeg("CD-R2004", prod_ident) ||
2358 strbeg("CD-R2006 ", prod_ident))
2359 usalp->dev = DEV_SONY_CDU_924;
2360 else if (strbeg("CD-R2006PLUS", prod_ident))
2361 usalp->dev = DEV_TEAC_CD_R50S;
2362 else if (strbeg("CD-RW226", prod_ident))
2363 usalp->dev = DEV_TEAC_CD_R50S;
2364 else if (strbeg("CD-R4012", prod_ident))
2365 usalp->dev = DEV_TEAC_CD_R50S;
2367 } else if (strbeg("SANYO", vendor_info)) {
2368 if (strbeg("CD-WO CRD-R24S", prod_ident))
2369 usalp->dev = DEV_CDD_521;
2371 } else if (strbeg("SONY", vendor_info)) {
2372 if (strbeg("CD-R CDU92", prod_ident) ||
2373 strbeg("CD-R CDU94", prod_ident))
2374 usalp->dev = DEV_SONY_CDU_924;
2376 } else if (strbeg("TEAC", vendor_info)) {
2377 if (strbeg("CD-R50S", prod_ident) ||
2378 strbeg("CD-R55S", prod_ident))
2379 usalp->dev = DEV_TEAC_CD_R50S;
2381 } else if (strbeg("TRAXDATA", vendor_info) ||
2382 strbeg("Traxdata", vendor_info)) {
2383 if (strbeg("CDR4120", prod_ident))
2384 usalp->dev = DEV_TEAC_CD_R50S;
2386 } else if (strbeg("T.YUDEN", vendor_info)) {
2387 if (strbeg("CD-WO EW-50", prod_ident))
2388 usalp->dev = DEV_TYUDEN_EW50;
2390 } else if (strbeg("WPI", vendor_info)) { /* Wearnes */
2391 if (strbeg("CDR-632P", prod_ident))
2392 usalp->dev = DEV_CDD_2600;
2394 } else if (strbeg("YAMAHA", vendor_info)) {
2395 if (strbeg("CDR10", prod_ident))
2396 usalp->dev = DEV_YAMAHA_CDR_100;
2397 if (strbeg("CDR200", prod_ident))
2398 usalp->dev = DEV_YAMAHA_CDR_400;
2399 if (strbeg("CDR400", prod_ident))
2400 usalp->dev = DEV_YAMAHA_CDR_400;
2402 } else if (strbeg("MATSHITA", vendor_info)) {
2403 if (strbeg("CD-R CW-7501", prod_ident))
2404 usalp->dev = DEV_MATSUSHITA_7501;
2405 if (strbeg("CD-R CW-7502", prod_ident))
2406 usalp->dev = DEV_MATSUSHITA_7502;
2408 if (usalp->dev == DEV_UNKNOWN) {
2410 * We do not have Manufacturer strings for
2411 * the following drives.
2413 if (strbeg("CDS615E", prod_ident)) /* Olympus */
2414 usalp->dev = DEV_SONY_CDU_924;
2416 if (usalp->dev == DEV_UNKNOWN && inq->type == INQ_ROMD) {
2424 usalp->dev = DEV_CDROM;
2426 if (mmc_check(usalp, &cdrr, &cdwr, &cdrrw, &cdwrw,
2428 usalp->dev = DEV_MMC_CDROM;
2430 usalp->dev = DEV_MMC_CDR;
2432 usalp->dev = DEV_MMC_CDRW;
2434 usalp->dev = DEV_MMC_DVD;
2436 usalp->dev = DEV_MMC_DVD_WR;
2441 if (strbeg("BERTHOLD", vendor_info)) {
2442 if (strbeg("", prod_ident))
2443 usalp->dev = DEV_HRSCAN;
2448 usalp->dev = DEV_MS300A;
2455 if (usalp->dev == DEV_UNKNOWN && !got_inquiry) {
2456 #ifdef PRINT_INQ_ERR
2457 usal_printerr(usalp);
2462 printinq(usalp, stdout);
2467 printinq(SCSI *usalp, FILE *f)
2469 register struct scsi_inquiry *inq = usalp->inq;
2471 fprintf(f, "Device type : ");
2472 usal_fprintdev(f, inq);
2473 fprintf(f, "Version : %d\n", inq->ansi_version);
2474 fprintf(f, "Response Format: %d\n", inq->data_format);
2475 if (inq->data_format >= 2) {
2476 fprintf(f, "Capabilities : ");
2477 if (inq->aenc) fprintf(f, "AENC ");
2478 if (inq->termiop) fprintf(f, "TERMIOP ");
2479 if (inq->reladr) fprintf(f, "RELADR ");
2480 if (inq->wbus32) fprintf(f, "WBUS32 ");
2481 if (inq->wbus16) fprintf(f, "WBUS16 ");
2482 if (inq->sync) fprintf(f, "SYNC ");
2483 if (inq->linked) fprintf(f, "LINKED ");
2484 if (inq->cmdque) fprintf(f, "CMDQUE ");
2485 if (inq->softreset) fprintf(f, "SOFTRESET ");
2488 if (inq->add_len >= 31 ||
2489 inq->vendor_info[0] ||
2490 inq->prod_ident[0] ||
2491 inq->prod_revision[0]) {
2492 fprintf(f, "Vendor_info : '%.8s'\n", inq->vendor_info);
2493 fprintf(f, "Identification : '%.16s'\n", inq->prod_ident);
2494 fprintf(f, "Revision : '%.4s'\n", inq->prod_revision);
2499 printdev(SCSI *usalp)
2501 printf("Device seems to be: ");
2503 switch (usalp->dev) {
2505 case DEV_UNKNOWN: printf("unknown"); break;
2506 case DEV_ACB40X0: printf("Adaptec 4000/4010/4070"); break;
2507 case DEV_ACB4000: printf("Adaptec 4000"); break;
2508 case DEV_ACB4010: printf("Adaptec 4010"); break;
2509 case DEV_ACB4070: printf("Adaptec 4070"); break;
2510 case DEV_ACB5500: printf("Adaptec 5500"); break;
2511 case DEV_ACB4520A: printf("Adaptec 4520A"); break;
2512 case DEV_ACB4525: printf("Adaptec 4525"); break;
2513 case DEV_MD21: printf("Emulex MD21"); break;
2514 case DEV_MD23: printf("Emulex MD23"); break;
2515 case DEV_NON_CCS_DSK: printf("Generic NON CCS Disk"); break;
2516 case DEV_CCS_GENDISK: printf("Generic CCS Disk"); break;
2517 case DEV_SONY_SMO: printf("Sony SMO-C501"); break;
2518 case DEV_MT02: printf("Emulex MT02"); break;
2519 case DEV_SC4000: printf("Sysgen SC4000"); break;
2520 case DEV_RXT800S: printf("Maxtor RXT800S"); break;
2521 case DEV_HRSCAN: printf("Berthold HR-Scanner"); break;
2522 case DEV_MS300A: printf("Microtek MS300A"); break;
2524 case DEV_CDROM: printf("Generic CD-ROM"); break;
2525 case DEV_MMC_CDROM: printf("Generic mmc CD-ROM"); break;
2526 case DEV_MMC_CDR: printf("Generic mmc CD-R"); break;
2527 case DEV_MMC_CDRW: printf("Generic mmc CD-RW"); break;
2528 case DEV_MMC_DVD: printf("Generic mmc2 DVD-ROM"); break;
2529 case DEV_MMC_DVD_WR: printf("Generic mmc2 DVD-R/DVD-RW"); break;
2530 case DEV_CDD_521_OLD: printf("Philips old CDD-521"); break;
2531 case DEV_CDD_521: printf("Philips CDD-521"); break;
2532 case DEV_CDD_522: printf("Philips CDD-522"); break;
2533 case DEV_PCD_600: printf("Kodak PCD-600"); break;
2534 case DEV_CDD_2000: printf("Philips CDD-2000"); break;
2535 case DEV_CDD_2600: printf("Philips CDD-2600"); break;
2536 case DEV_YAMAHA_CDR_100:printf("Yamaha CDR-100"); break;
2537 case DEV_YAMAHA_CDR_400:printf("Yamaha CDR-400"); break;
2538 case DEV_PLASMON_RF_4100:printf("Plasmon RF-4100"); break;
2539 case DEV_SONY_CDU_924: printf("Sony CDU-924S"); break;
2540 case DEV_RICOH_RO_1060C:printf("Ricoh RO-1060C"); break;
2541 case DEV_RICOH_RO_1420C:printf("Ricoh RO-1420C"); break;
2542 case DEV_TEAC_CD_R50S: printf("Teac CD-R50S"); break;
2543 case DEV_MATSUSHITA_7501:printf("Matsushita CW-7501"); break;
2544 case DEV_MATSUSHITA_7502:printf("Matsushita CW-7502"); break;
2546 case DEV_PIONEER_DW_S114X: printf("Pioneer DW-S114X"); break;
2547 case DEV_PIONEER_DVDR_S101:printf("Pioneer DVD-R S101"); break;
2549 default: printf("Missing Entry for dev %d",
2558 do_inquiry(SCSI *usalp, int print)
2560 if (getdev(usalp, print)) {
2570 recovery_needed(SCSI *usalp, cdr_t *dp)
2573 register struct usal_cmd *scmd = usalp->scmd;
2576 err = test_unit_ready(usalp);
2581 else if (scmd->error >= SCG_FATAL) /* nicht selektierbar */
2584 if (scmd->sense.code < 0x70) /* non extended Sense */
2587 /* XXX Old Philips code */
2588 return (((struct scsi_ext_sense *)&scmd->sense)->sense_code == 0xD0);
2592 scsi_load(SCSI *usalp, cdr_t *dp)
2597 if ((dp->cdr_flags & CDR_CADDYLOAD) == 0) {
2598 if (scsi_start_stop_unit(usalp, 1, 1, dp && (dp->cdr_cmdflags&F_IMMED)) >= 0)
2602 if (wait_unit_ready(usalp, 60))
2605 key = usal_sense_key(usalp);
2606 code = usal_sense_code(usalp);
2608 if (key == SC_NOT_READY && (code == 0x3A || code == 0x30)) {
2609 errmsgno(EX_BAD, "Cannot load media with %s drive!\n",
2610 (dp->cdr_flags & CDR_CADDYLOAD) ? "caddy" : "this");
2611 errmsgno(EX_BAD, "Try to load media by hand.\n");
2617 scsi_unload(SCSI *usalp, cdr_t *dp)
2619 return (scsi_start_stop_unit(usalp, 0, 1, dp && (dp->cdr_cmdflags&F_IMMED)));
2623 scsi_cdr_write(SCSI *usalp,
2624 caddr_t bp /* address of buffer */,
2625 long sectaddr /* disk address (sector) to put */,
2626 long size /* number of bytes to transfer */,
2627 int blocks /* sector count */,
2628 BOOL islast /* last write for track */)
2630 return (write_xg1(usalp, bp, sectaddr, size, blocks));
2633 struct cd_mode_page_2A *
2634 mmc_cap(SCSI *usalp, Uchar *modep)
2639 struct cd_mode_page_2A *mp;
2640 struct cd_mode_page_2A *mp2;
2644 fillbytes((caddr_t)mode, sizeof (mode), '\0');
2646 if (!get_mode_params(usalp, 0x2A, "CD capabilities",
2647 mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
2649 if (usal_sense_key(usalp) == SC_NOT_READY) {
2650 if (wait_unit_ready(usalp, 60))
2653 return (NULL); /* Pre SCSI-3/mmc drive */
2656 if (len == 0) /* Pre SCSI-3/mmc drive */
2659 mp = (struct cd_mode_page_2A *)
2660 (mode + sizeof (struct scsi_mode_header) +
2661 ((struct scsi_mode_header *)mode)->blockdesc_len);
2664 * Do some heuristics against pre SCSI-3/mmc VU page 2A
2665 * We should test for a minimum p_len of 0x14, but some
2666 * buggy CD-ROM readers ommit the write speed values.
2668 if (mp->p_len < 0x10)
2671 val = a_to_u_2_byte(mp->max_read_speed);
2672 if (val != 0 && val < 176)
2675 val = a_to_u_2_byte(mp->cur_read_speed);
2676 if (val != 0 && val < 176)
2679 len -= sizeof (struct scsi_mode_header) +
2680 ((struct scsi_mode_header *)mode)->blockdesc_len;
2682 mp2 = (struct cd_mode_page_2A *)modep;
2686 movebytes(mp, mp2, len);
2692 mmc_getval(struct cd_mode_page_2A *mp,
2693 BOOL *cdrrp /* CD ROM */,
2694 BOOL *cdwrp /* CD-R writer */,
2695 BOOL *cdrrwp /* CD-RW reader */,
2696 BOOL *cdwrwp /* CD-RW writer */,
2697 BOOL *dvdp /* DVD reader */,
2698 BOOL *dvdwp /* DVD writer */)
2700 BOOL isdvd; /* Any DVD reader */
2701 BOOL isdvd_wr; /* DVD writer (R / RAM) */
2702 BOOL iscd_wr; /* CD writer */
2704 iscd_wr = (mp->cd_r_write != 0) || /* SCSI-3/mmc CD-R */
2705 (mp->cd_rw_write != 0); /* SCSI-3/mmc CD-RW */
2708 *cdrrp = (mp->cd_r_read != 0); /* SCSI-3/mmc CD */
2710 *cdwrp = (mp->cd_r_write != 0); /* SCSI-3/mmc CD-R */
2713 *cdrrwp = (mp->cd_rw_read != 0); /* SCSI-3/mmc CD */
2715 *cdwrwp = (mp->cd_rw_write != 0); /* SCSI-3/mmc CD-RW */
2717 isdvd = /* SCSI-3/mmc2 DVD */
2718 (mp->dvd_ram_read + mp->dvd_r_read +
2719 mp->dvd_rom_read) != 0;
2721 isdvd_wr = /* SCSI-3/mmc2 DVD writer*/
2722 (mp->dvd_ram_write + mp->dvd_r_write) != 0;
2731 is_mmc(SCSI *usalp, BOOL *cdwp, BOOL *dvdwp)
2741 if (!mmc_check(usalp, NULL, &cdwr, NULL, &cdwrw, NULL, dvdwp))
2745 *cdwp = cdwr | cdwrw;
2751 mmc_check(SCSI *usalp,
2752 BOOL *cdrrp /* CD ROM */,
2753 BOOL *cdwrp /* CD-R writer */,
2754 BOOL *cdrrwp /* CD-RW reader */,
2755 BOOL *cdwrwp /* CD-RW writer */,
2756 BOOL *dvdp /* DVD reader */,
2757 BOOL *dvdwp /* DVD writer */)
2761 struct cd_mode_page_2A *mp;
2763 if (usalp->inq->type != INQ_ROMD)
2766 fillbytes((caddr_t)mode, sizeof (mode), '\0');
2768 was_atapi = allow_atapi(usalp, TRUE);
2770 mp = mmc_cap(usalp, mode);
2772 allow_atapi(usalp, was_atapi);
2776 mmc_getval(mp, cdrrp, cdwrp, cdrrwp, cdwrwp, dvdp, dvdwp);
2778 return (TRUE); /* Generic SCSI-3/mmc CD */
2782 print_speed(char *fmt, int val)
2784 printf(" %s: %5d kB/s", fmt, val);
2785 printf(" (CD %3ux,", val/176);
2786 printf(" DVD %2ux)\n", val/1385);
2789 #define DOES(what, flag) printf(" Does %s%s\n", flag?"":"not ", what)
2790 #define IS(what, flag) printf(" Is %s%s\n", flag?"":"not ", what)
2791 #define VAL(what, val) printf(" %s: %d\n", what, val[0]*256 + val[1])
2792 #define SVAL(what, val) printf(" %s: %s\n", what, val)
2795 print_capabilities(SCSI *usalp)
2799 struct cd_mode_page_2A *mp;
2800 static const char *bclk[4] = {"32", "16", "24", "24 (I2S)"};
2801 static const char *load[8] = {"caddy", "tray", "pop-up", "reserved(3)",
2802 "disc changer", "cartridge changer",
2803 "reserved(6)", "reserved(7)" };
2804 static const char *rotctl[4] = {"CLV/PCAV", "CAV", "reserved(2)", "reserved(3)"};
2807 if (usalp->inq->type != INQ_ROMD)
2810 fillbytes((caddr_t)mode, sizeof (mode), '\0');
2812 was_atapi = allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */
2814 mp = mmc_cap(usalp, mode);
2816 allow_atapi(usalp, was_atapi);
2820 printf("\nDrive capabilities, per");
2821 if (mp->p_len >= 28)
2823 else if (mp->p_len >= 24)
2827 printf(" page 2A:\n\n");
2829 DOES("read CD-R media", mp->cd_r_read);
2830 DOES("write CD-R media", mp->cd_r_write);
2831 DOES("read CD-RW media", mp->cd_rw_read);
2832 DOES("write CD-RW media", mp->cd_rw_write);
2833 DOES("read DVD-ROM media", mp->dvd_rom_read);
2834 DOES("read DVD-R media", mp->dvd_r_read);
2835 DOES("write DVD-R media", mp->dvd_r_write);
2836 DOES("read DVD-RAM media", mp->dvd_ram_read);
2837 DOES("write DVD-RAM media", mp->dvd_ram_write);
2838 DOES("support test writing", mp->test_write);
2840 DOES("read Mode 2 Form 1 blocks", mp->mode_2_form_1);
2841 DOES("read Mode 2 Form 2 blocks", mp->mode_2_form_2);
2842 DOES("read digital audio blocks", mp->cd_da_supported);
2843 if (mp->cd_da_supported)
2844 DOES("restart non-streamed digital audio reads accurately", mp->cd_da_accurate);
2845 DOES("support Buffer-Underrun-Free recording", mp->BUF);
2846 DOES("read multi-session CDs", mp->multi_session);
2847 DOES("read fixed-packet CD media using Method 2", mp->method2);
2848 DOES("read CD bar code", mp->read_bar_code);
2849 DOES("read R-W subcode information", mp->rw_supported);
2850 if (mp->rw_supported)
2851 DOES("return R-W subcode de-interleaved and error-corrected", mp->rw_deint_corr);
2852 DOES("read raw P-W subcode data from lead in", mp->pw_in_lead_in);
2853 DOES("return CD media catalog number", mp->UPC);
2854 DOES("return CD ISRC information", mp->ISRC);
2855 DOES("support C2 error pointers", mp->c2_pointers);
2856 DOES("deliver composite A/V data", mp->composite);
2858 DOES("play audio CDs", mp->audio_play);
2859 if (mp->audio_play) {
2860 VAL("Number of volume control levels", mp->num_vol_levels);
2861 DOES("support individual volume control setting for each channel", mp->sep_chan_vol);
2862 DOES("support independent mute setting for each channel", mp->sep_chan_mute);
2863 DOES("support digital output on port 1", mp->digital_port_1);
2864 DOES("support digital output on port 2", mp->digital_port_2);
2865 if (mp->digital_port_1 || mp->digital_port_2) {
2866 DOES("send digital data LSB-first", mp->LSBF);
2867 DOES("set LRCK high for left-channel data", mp->RCK);
2868 DOES("have valid data on falling edge of clock", mp->BCK);
2869 SVAL("Length of data in BCLKs", bclk[mp->length]);
2873 SVAL("Loading mechanism type", load[mp->loading_type]);
2874 DOES("support ejection of CD via START/STOP command", mp->eject);
2875 DOES("lock media on power up via prevent jumper", mp->prevent_jumper);
2876 DOES("allow media to be locked in the drive via PREVENT/ALLOW command", mp->lock);
2877 IS("currently in a media-locked state", mp->lock_state);
2878 DOES("support changing side of disk", mp->side_change);
2879 DOES("have load-empty-slot-in-changer feature", mp->sw_slot_sel);
2880 DOES("support Individual Disk Present feature", mp->disk_present_rep);
2882 print_speed("Maximum read speed", a_to_u_2_byte(mp->max_read_speed));
2883 print_speed("Current read speed", a_to_u_2_byte(mp->cur_read_speed));
2884 print_speed("Maximum write speed", a_to_u_2_byte(mp->max_write_speed));
2885 if (mp->p_len >= 28)
2886 print_speed("Current write speed", a_to_u_2_byte(mp->v3_cur_write_speed));
2888 print_speed("Current write speed", a_to_u_2_byte(mp->cur_write_speed));
2889 if (mp->p_len >= 28) {
2890 SVAL("Rotational control selected", rotctl[mp->rot_ctl_sel]);
2892 VAL("Buffer size in KB", mp->buffer_size);
2894 if (mp->p_len >= 24) {
2895 VAL("Copy management revision supported", mp->copy_man_rev);
2898 if (mp->p_len >= 28) {
2899 struct cd_wr_speed_performance *pp;
2904 ndesc = a_to_u_2_byte(mp->num_wr_speed_des);
2905 pp = mp->wr_speed_des;
2906 printf(" Number of supported write speeds: %d\n", ndesc);
2907 for (i = 0; i < ndesc; i++, pp++) {
2908 printf(" Write speed # %d:", i);
2909 n = a_to_u_2_byte(pp->wr_speed_supp);
2910 printf(" %5d kB/s", n);
2911 printf(" %s", rotctl[pp->rot_ctl_sel]);
2912 printf(" (CD %3ux,", n/176);
2913 printf(" DVD %2ux)\n", n/1385);
2917 /* Generic SCSI-3/mmc CD */