Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / scsi_cdr.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)scsi_cdr.c       1.137 04/05/25 Copyright 1995-2004 J. Schilling */
14 /*
15  *      SCSI command functions for cdrecord
16  *      covering pre-MMC standard functions up to MMC-2
17  *
18  *      Copyright (c) 1995-2004 J. Schilling
19  */
20 /*
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.
24  *
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.
29  *
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.
33  */
34
35 /*
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.
42  */
43 #include <mconfig.h>
44
45 #include <stdio.h>
46 #include <standard.h>
47 #include <stdxlib.h>
48 #include <unixstd.h>
49 #include <fctldefs.h>
50 #include <errno.h>
51 #include <strdefs.h>
52 #include <timedefs.h>
53
54 #include <utypes.h>
55 #include <btorder.h>
56 #include <intcvt.h>
57 #include <schily.h>
58
59 #include <usal/usalcmd.h>
60 #include <usal/scsidefs.h>
61 #include <usal/scsireg.h>
62 #include <usal/scsitransp.h>
63
64 #include "scsimmc.h"
65 #include "wodim.h"
66 #include "scsi_scan.h"
67
68 #define strbeg(s1, s2)  (strstr((s2), (s1)) == (s2))
69
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, 
99                                                          int subq, int fmt);
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, 
108                                                                  int fmt);
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 *, 
131                                                         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);
159
160 BOOL
161 unit_ready(SCSI *usalp)
162 {
163         register struct usal_cmd        *scmd = usalp->scmd;
164
165         if (test_unit_ready(usalp) >= 0)                /* alles OK */
166                 return (TRUE);
167         else if (scmd->error >= SCG_FATAL)      /* nicht selektierbar */
168                 return (FALSE);
169
170         if (usal_sense_key(usalp) == SC_UNIT_ATTENTION) {
171                 if (test_unit_ready(usalp) >= 0)        /* alles OK */
172                         return (TRUE);
173         }
174         if ((usal_cmd_status(usalp) & ST_BUSY) != 0) {
175                 /*
176                  * Busy/reservation_conflict
177                  */
178                 usleep(500000);
179                 if (test_unit_ready(usalp) >= 0)        /* alles OK */
180                         return (TRUE);
181         }
182         if (usal_sense_key(usalp) == -1) {      /* non extended Sense */
183                 if (usal_sense_code(usalp) == 4)        /* NOT_READY */
184                         return (FALSE);
185                 return (TRUE);
186         }
187                                                 /* FALSE wenn NOT_READY */
188         return (usal_sense_key(usalp) != SC_NOT_READY);
189 }
190
191 BOOL
192 wait_unit_ready(SCSI *usalp, int secs)
193 {
194         int     i;
195         int     c;
196         int     k;
197         int     ret;
198
199         usalp->silent++;
200         ret = test_unit_ready(usalp);           /* eat up unit attention */
201         if (ret < 0)
202                 ret = test_unit_ready(usalp);   /* got power on condition? */
203         usalp->silent--;
204
205         if (ret >= 0)                           /* success that's enough */
206                 return (TRUE);
207
208         usalp->silent++;
209         for (i = 0; i < secs && (ret = test_unit_ready(usalp)) < 0; i++) {
210                 if (usalp->scmd->scb.busy != 0) {
211                         sleep(1);
212                         continue;
213                 }
214                 c = usal_sense_code(usalp);
215                 k = usal_sense_key(usalp);
216                 /*
217                  * Abort quickly if it does not make sense to wait.
218                  * 0x30 == Cannot read medium
219                  * 0x3A == Medium not present
220                  */
221                 if ((k == SC_NOT_READY && (c == 0x3A || c == 0x30)) ||
222                     (k == SC_MEDIUM_ERROR)) {
223                         if (usalp->silent <= 1)
224                                 usal_printerr(usalp);
225                         usalp->silent--;
226                         return (FALSE);
227                 }
228                 sleep(1);
229         }
230         usalp->silent--;
231         if (ret < 0)
232                 return (FALSE);
233         return (TRUE);
234 }
235
236 BOOL
237 scsi_in_progress(SCSI *usalp)
238 {
239         if (usal_sense_key(usalp) == SC_NOT_READY &&
240                 /*
241                  * Logigal unit not ready operation/long_write in progress
242                  */
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"    */
247                 return (TRUE);
248         } else {
249                 if (usalp->silent <= 1)
250                         usal_printerr(usalp);
251         }
252         return (FALSE);
253 }
254
255 BOOL
256 cdr_underrun(SCSI *usalp)
257 {
258         if ((usal_sense_key(usalp) != SC_ILLEGAL_REQUEST &&
259             usal_sense_key(usalp) != SC_MEDIUM_ERROR))
260                 return (FALSE);
261
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 */
265
266             (usal_sense_code(usalp) == 0x0C &&
267             usal_sense_qual(usalp) == 0x09)) {  /* write error - loss of streaming */
268                 return (TRUE);
269         }
270         /*
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...
274          */
275         return (FALSE);
276 }
277
278 int
279 test_unit_ready(SCSI *usalp)
280 {
281         register struct usal_cmd        *scmd = usalp->scmd;
282
283         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
284         scmd->addr = (caddr_t)0;
285         scmd->size = 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);
291
292         usalp->cmdname = "test unit ready";
293
294         return (usal_cmd(usalp));
295 }
296
297 int
298 rezero_unit(SCSI *usalp)
299 {
300         register struct usal_cmd        *scmd = usalp->scmd;
301
302         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
303         scmd->addr = (caddr_t)0;
304         scmd->size = 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);
310
311         usalp->cmdname = "rezero unit";
312
313         return (usal_cmd(usalp));
314 }
315
316 int
317 request_sense(SCSI *usalp)
318 {
319                 char    sensebuf[CCS_SENSE_LEN];
320         register struct usal_cmd        *scmd = usalp->scmd;
321
322
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;
332
333         usalp->cmdname = "request_sense";
334
335         if (usal_cmd(usalp) < 0)
336                 return (-1);
337         usal_prsense((Uchar *)sensebuf, CCS_SENSE_LEN - usal_getresid(usalp));
338         return (0);
339 }
340
341 int
342 request_sense_b(SCSI *usalp, caddr_t bp, int cnt)
343 {
344         register struct usal_cmd        *scmd = usalp->scmd;
345
346
347         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
348         scmd->addr = bp;
349         scmd->size = cnt;
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;
356
357         usalp->cmdname = "request_sense";
358
359         if (usal_cmd(usalp) < 0)
360                 return (-1);
361         return (0);
362 }
363
364 int
365 inquiry(SCSI *usalp, caddr_t bp, int cnt)
366 {
367         register struct usal_cmd        *scmd = usalp->scmd;
368
369         fillbytes(bp, cnt, '\0');
370         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
371         scmd->addr = bp;
372         scmd->size = cnt;
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;
379
380         usalp->cmdname = "inquiry";
381
382         if (usal_cmd(usalp) < 0)
383                 return (-1);
384         if (usalp->verbose)
385                 usal_prbytes("Inquiry Data   :", (Uchar *)bp, cnt - usal_getresid(usalp));
386         return (0);
387 }
388
389 int
390 read_capacity(SCSI *usalp)
391 {
392         register struct usal_cmd        *scmd = usalp->scmd;
393
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 */
403
404         usalp->cmdname = "read capacity";
405
406         if (usal_cmd(usalp) < 0) {
407                 return (-1);
408         } else {
409                 long    cbsize;
410                 long    cbaddr;
411
412                 /*
413                  * c_bsize & c_baddr are signed Int32_t
414                  * so we use signed int conversion here.
415                  */
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;
420         }
421         return (0);
422 }
423
424 void
425 print_capacity(SCSI *usalp, FILE *f)
426 {
427         long    kb;
428         long    mb;
429         long    prmb;
430         double  dkb;
431
432         dkb =  (usalp->cap->c_baddr+1.0) * (usalp->cap->c_bsize/1024.0);
433         kb = dkb;
434         mb = dkb / 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);
439 }
440
441 int
442 scsi_load_unload(SCSI *usalp, int load)
443 {
444         register struct usal_cmd        *scmd = usalp->scmd;
445
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 # */
454
455         usalp->cmdname = "medium load/unload";
456
457         if (usal_cmd(usalp) < 0)
458                 return (-1);
459         return (0);
460 }
461
462 int
463 scsi_prevent_removal(SCSI *usalp, int prevent)
464 {
465         register struct usal_cmd        *scmd = usalp->scmd;
466
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;
474
475         usalp->cmdname = "prevent/allow medium removal";
476
477         if (usal_cmd(usalp) < 0)
478                 return (-1);
479         return (0);
480 }
481
482
483 int
484 scsi_start_stop_unit(SCSI *usalp, int flg, int loej, BOOL immed)
485 {
486         register struct usal_cmd        *scmd = usalp->scmd;
487
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);
495
496         if (immed)
497                 scmd->cdb.cmd_cdb[1] |= 0x01;
498
499         usalp->cmdname = "start/stop unit";
500
501         return (usal_cmd(usalp));
502 }
503
504 int
505 scsi_set_streaming(SCSI *usalp, caddr_t perf_desc, int size)
506 {
507         register struct usal_cmd        *scmd = usalp->scmd;
508
509         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
510         scmd->addr = perf_desc;
511         scmd->size = size;
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;
518
519         usalp->cmdname = "set streaming";
520
521   if(usalp->verbose) 
522      fprintf(stderr, "scsi_set_streaming\n");
523         if (usal_cmd(usalp) < 0)
524                 return (-1);
525         return (0);
526 }
527     
528 int
529 scsi_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl)
530 {
531         register struct usal_cmd        *scmd = usalp->scmd;
532
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);
539
540         if (readspeed < 0)
541                 i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], 0xFFFF);
542         else
543                 i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], readspeed);
544         if (writespeed < 0)
545                 i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xFFFF);
546         else
547                 i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], writespeed);
548
549         scmd->cdb.cmd_cdb[1] |= rotctl & 0x03;
550
551         usalp->cmdname = "set cd speed";
552
553         if (usal_cmd(usalp) < 0)
554                 return (-1);
555         return (0);
556 }
557
558 int
559 scsi_get_speed(SCSI *usalp, int *readspeedp, int *writespeedp)
560 {
561         struct  cd_mode_page_2A *mp;
562         Uchar   m[256];
563         int     val;
564
565         usalp->silent++;
566         mp = mmc_cap(usalp, m); /* Get MMC capabilities in allocated mp */
567         usalp->silent--;
568         if (mp == NULL)
569                 return (-1);    /* Pre SCSI-3/mmc drive         */
570
571         val = a_to_u_2_byte(mp->cur_read_speed);
572         if (readspeedp)
573                 *readspeedp = val;
574
575         if (mp->p_len >= 28)
576                 val = a_to_u_2_byte(mp->v3_cur_write_speed);
577         else
578                 val = a_to_u_2_byte(mp->cur_write_speed);
579         if (writespeedp)
580                 *writespeedp = val;
581
582         return (0);
583 }
584
585
586 int
587 qic02(SCSI *usalp, int cmd)
588 {
589         register struct usal_cmd        *scmd = usalp->scmd;
590
591         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
592         scmd->addr = (caddr_t)0;
593         scmd->size = 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;
600
601         usalp->cmdname = "qic 02";
602         return (usal_cmd(usalp));
603 }
604
605 #define G0_MAXADDR      0x1FFFFFL
606
607 int 
608 write_xscsi(SCSI *usalp, caddr_t bp, long addr, long size, int cnt)
609 {
610         if (addr <= G0_MAXADDR)
611                 return (write_xg0(usalp, bp, addr, size, cnt));
612         else
613                 return (write_xg1(usalp, bp, addr, size, cnt));
614 }
615
616 int 
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 */)
622 {
623         register struct usal_cmd        *scmd = usalp->scmd;
624
625         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
626         scmd->addr = bp;
627         scmd->size = size;
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;
636
637         usalp->cmdname = "write_g0";
638
639         if (usal_cmd(usalp) < 0)
640                 return (-1);
641         return (size - usal_getresid(usalp));
642 }
643
644 int 
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 */)
650 {
651         register struct usal_cmd        *scmd = usalp->scmd;
652
653         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
654         scmd->addr = bp;
655         scmd->size = size;
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);
664
665         usalp->cmdname = "write_g1";
666
667         if (usal_cmd(usalp) < 0)
668                 return (-1);
669         return (size - usal_getresid(usalp));
670 }
671
672 int 
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 */)
678 {
679         register struct usal_cmd        *scmd = usalp->scmd;
680
681         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
682         scmd->addr = bp;
683         scmd->size = size;
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);
692
693         usalp->cmdname = "write_g5";
694
695         if (usal_cmd(usalp) < 0)
696                 return (-1);
697         return (size - usal_getresid(usalp));
698 }
699
700 int
701 seek_scsi(SCSI *usalp, long addr)
702 {
703         if (addr <= G0_MAXADDR)
704                 return (seek_g0(usalp, addr));
705         else
706                 return (seek_g1(usalp, addr));
707 }
708
709 int
710 seek_g0(SCSI *usalp, long addr)
711 {
712         register struct usal_cmd        *scmd = usalp->scmd;
713
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);
721
722         usalp->cmdname = "seek_g0";
723
724         return (usal_cmd(usalp));
725 }
726
727 int
728 seek_g1(SCSI *usalp, long addr)
729 {
730         register struct usal_cmd        *scmd = usalp->scmd;
731
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);
739
740         usalp->cmdname = "seek_g1";
741
742         return (usal_cmd(usalp));
743 }
744
745 int
746 scsi_flush_cache(SCSI *usalp, BOOL immed)
747 {
748         register struct usal_cmd        *scmd = usalp->scmd;
749
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);
757
758         if (immed)
759                 scmd->cdb.cmd_cdb[1] |= 0x02;
760
761         usalp->cmdname = "flush cache";
762
763         if (usal_cmd(usalp) < 0)
764                 return (-1);
765         return (0);
766 }
767
768 int
769 read_buffer(SCSI *usalp, caddr_t bp, int cnt, int mode)
770 {
771         register struct usal_cmd        *scmd = usalp->scmd;
772
773         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
774         scmd->addr = bp;
775         scmd->size = cnt;
776         scmd->dma_read = 1;
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);
783
784         usalp->cmdname = "read buffer";
785
786         return (usal_cmd(usalp));
787 }
788
789 int
790 write_buffer(SCSI *usalp, char *buffer, long length, int mode, int bufferid, 
791              long offset)
792 {
793         register struct usal_cmd        *scmd = usalp->scmd;
794         char                    *cdb;
795
796         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
797         scmd->addr = buffer;
798         scmd->size = length;
799         scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
800         scmd->cdb_len = SC_G1_CDBLEN;
801         scmd->sense_len = CCS_SENSE_LEN;
802
803         cdb = (char *)scmd->cdb.cmd_cdb;
804
805         cdb[0] = 0x3B;
806         cdb[1] = mode & 7;
807         cdb[2] = bufferid;
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;
814
815         usalp->cmdname = "write_buffer";
816
817         if (usal_cmd(usalp) >= 0)
818                 return (1);
819         return (0);
820 }
821
822 int
823 read_subchannel(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int subq, 
824                                          int fmt)
825
826 {
827         register struct usal_cmd        *scmd = usalp->scmd;
828
829         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
830         scmd->addr = bp;
831         scmd->size = cnt;
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);
837         if (msf)
838                 scmd->cdb.g1_cdb.res = 1;
839         if (subq)
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);
844
845         usalp->cmdname = "read subchannel";
846
847         if (usal_cmd(usalp) < 0)
848                 return (-1);
849         return (0);
850 }
851
852 int
853 read_toc(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int fmt)
854 {
855         register struct usal_cmd        *scmd = usalp->scmd;
856
857         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
858         scmd->addr = bp;
859         scmd->size = cnt;
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);
865         if (msf)
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);
870
871         usalp->cmdname = "read toc";
872
873         if (usal_cmd(usalp) < 0)
874                 return (-1);
875         return (0);
876 }
877
878 int
879 read_toc_philips(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int fmt)
880 {
881         register struct usal_cmd        *scmd = usalp->scmd;
882
883         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
884         scmd->addr = bp;
885         scmd->size = cnt;
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);
892         if (msf)
893                 scmd->cdb.g1_cdb.res = 1;
894         scmd->cdb.g1_cdb.res6 = track;
895         g1_cdblen(&scmd->cdb.g1_cdb, cnt);
896
897         if (fmt & 1)
898                 scmd->cdb.g1_cdb.vu_96 = 1;
899         if (fmt & 2)
900                 scmd->cdb.g1_cdb.vu_97 = 1;
901
902         usalp->cmdname = "read toc";
903
904         if (usal_cmd(usalp) < 0)
905                 return (-1);
906         return (0);
907 }
908
909 int
910 read_header(SCSI *usalp, caddr_t bp, long addr, int cnt, int msf)
911 {
912         register struct usal_cmd        *scmd = usalp->scmd;
913
914         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
915         scmd->addr = bp;
916         scmd->size = cnt;
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);
922         if (msf)
923                 scmd->cdb.g1_cdb.res = 1;
924         g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
925         g1_cdblen(&scmd->cdb.g1_cdb, cnt);
926
927         usalp->cmdname = "read header";
928
929         if (usal_cmd(usalp) < 0)
930                 return (-1);
931         return (0);
932 }
933
934 int
935 read_disk_info(SCSI *usalp, caddr_t bp, int cnt)
936 {
937         register struct usal_cmd        *scmd = usalp->scmd;
938
939         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
940         scmd->addr = bp;
941         scmd->size = cnt;
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);
949
950         usalp->cmdname = "read disk info";
951
952         if (usal_cmd(usalp) < 0)
953                 return (-1);
954         return (0);
955 }
956
957 int
958 read_track_info(SCSI *usalp, caddr_t bp, int type, int addr, int cnt)
959 {
960         register struct usal_cmd        *scmd = usalp->scmd;
961
962         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
963         scmd->addr = bp;
964         scmd->size = cnt;
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);
975
976         usalp->cmdname = "read track info";
977
978         if (usal_cmd(usalp) < 0)
979                 return (-1);
980         return (0);
981 }
982
983 int
984 reserve_track(SCSI *usalp, Ulong size)
985 {
986         register struct usal_cmd        *scmd = usalp->scmd;
987
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);
995
996         usalp->cmdname = "reserve track";
997
998         if (usal_cmd(usalp) < 0) 
999                 return (-1);
1000
1001         return (0);
1002
1003 }
1004
1005 int
1006 read_rzone_info(SCSI *usalp, caddr_t bp, int cnt)
1007 {
1008         return (read_track_info(usalp, bp, TI_TYPE_LBA, 0, cnt));
1009 }
1010
1011 int
1012 reserve_tr_rzone(SCSI *usalp, long size /* number of blocks */)
1013 {
1014         register struct usal_cmd        *scmd = usalp->scmd;
1015
1016         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1017         scmd->addr = (caddr_t)0;
1018         scmd->size = 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);
1024
1025         i_to_4_byte(&scmd->cdb.g1_cdb.addr[3], size);
1026
1027         usalp->cmdname = "reserve_track_rzone";
1028
1029         if (usal_cmd(usalp) < 0)
1030                 return (-1);
1031         return (0);
1032 }
1033
1034 int
1035 read_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int addr, int layer, 
1036                    int fmt)
1037 {
1038         register struct usal_cmd        *scmd = usalp->scmd;
1039
1040         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1041         scmd->addr = bp;
1042         scmd->size = cnt;
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;
1053
1054         usalp->cmdname = "read dvd structure";
1055
1056         if (usal_cmd(usalp) < 0)
1057                 return (-1);
1058         return (0);
1059 }
1060
1061 int
1062 send_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int layer, int fmt)
1063 {
1064         register struct usal_cmd        *scmd = usalp->scmd;
1065
1066         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1067         scmd->addr = bp;
1068         scmd->size = cnt;
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);
1076
1077         scmd->cdb.cmd_cdb[7] = fmt;
1078
1079         usalp->cmdname = "send dvd structure";
1080
1081         if (usal_cmd(usalp) < 0)
1082                 return (-1);
1083         return (0);
1084 }
1085
1086 int
1087 send_opc(SCSI *usalp, caddr_t bp, int cnt, int doopc)
1088 {
1089         register struct usal_cmd        *scmd = usalp->scmd;
1090
1091         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1092         scmd->addr = bp;
1093         scmd->size = cnt;
1094         scmd->flags = SCG_DISRE_ENA;
1095         scmd->cdb_len = SC_G1_CDBLEN;
1096         scmd->sense_len = CCS_SENSE_LEN;
1097         scmd->timeout = 60;
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);
1102
1103         usalp->cmdname = "send opc";
1104
1105         if (usal_cmd(usalp) < 0)
1106                 return (-1);
1107         return (0);
1108 }
1109
1110 int
1111 read_track_info_philips(SCSI *usalp, caddr_t bp, int track, int cnt)
1112 {
1113         register struct usal_cmd        *scmd = usalp->scmd;
1114
1115         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1116         scmd->addr = bp;
1117         scmd->size = cnt;
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);
1125
1126         usalp->cmdname = "read track info";
1127
1128         if (usal_cmd(usalp) < 0)
1129                 return (-1);
1130         return (0);
1131 }
1132
1133 int
1134 scsi_close_tr_session(SCSI *usalp, int type, int track, BOOL immed)
1135 {
1136         register struct usal_cmd        *scmd = usalp->scmd;
1137
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;
1147
1148         if (immed)
1149                 scmd->cdb.g1_cdb.reladr = 1;
1150 /*              scmd->cdb.cmd_cdb[1] |= 0x01;*/
1151 #ifdef  nono
1152         scmd->cdb.g1_cdb.reladr = 1;    /* IMM hack to test Mitsumi behaviour*/
1153 #endif
1154
1155         usalp->cmdname = "close track/session";
1156
1157         if (usal_cmd(usalp) < 0)
1158                 return (-1);
1159         return (0);
1160 }
1161
1162 int
1163 read_master_cue(SCSI *usalp, caddr_t bp, int sheet, int cnt)
1164 {
1165         register struct usal_cmd        *scmd = usalp->scmd;
1166
1167         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1168         scmd->addr = bp;
1169         scmd->size = cnt;
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);
1177
1178         usalp->cmdname = "read master cue";
1179
1180         if (usal_cmd(usalp) < 0)
1181                 return (-1);
1182         return (0);
1183 }
1184
1185 int
1186 send_cue_sheet(SCSI *usalp, caddr_t bp, long size)
1187 {
1188         register struct usal_cmd        *scmd = usalp->scmd;
1189
1190         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1191         scmd->addr = bp;
1192         scmd->size = size;
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);
1199
1200         usalp->cmdname = "send_cue_sheet";
1201
1202         if (usal_cmd(usalp) < 0)
1203                 return (-1);
1204         return (size - scmd->resid);
1205 }
1206
1207 int
1208 read_buff_cap(SCSI *usalp, long *sp, long *fp)
1209 {
1210         char    resp[12];
1211         Ulong   freespace;
1212         Ulong   bufsize;
1213         int     per;
1214         register struct usal_cmd        *scmd = usalp->scmd;
1215
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));
1225
1226         usalp->cmdname = "read buffer cap";
1227
1228         if (usal_cmd(usalp) < 0)
1229                 return (-1);
1230
1231         bufsize   = a_to_u_4_byte(&resp[4]);
1232         freespace = a_to_u_4_byte(&resp[8]);
1233         if (sp)
1234                 *sp = bufsize;
1235         if (fp)
1236                 *fp = freespace;
1237
1238         if (usalp->verbose || (sp == 0 && fp == 0))
1239                 printf("BFree: %ld K BSize: %ld K\n", freespace >> 10, bufsize >> 10);
1240
1241         if (bufsize == 0)
1242                 return (0);
1243         per = (100 * (bufsize - freespace)) / bufsize;
1244         if (per < 0)
1245                 return (0);
1246         if (per > 100)
1247                 return (100);
1248         return (per);
1249 }
1250
1251 int
1252 scsi_blank(SCSI *usalp, long addr, int blanktype, BOOL immed)
1253 {
1254         register struct usal_cmd        *scmd = usalp->scmd;
1255
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);
1264
1265         if (immed)
1266                 scmd->cdb.g5_cdb.res |= 8;
1267 /*              scmd->cdb.cmd_cdb[1] |= 0x10;*/
1268
1269         usalp->cmdname = "blank unit";
1270
1271         return (usal_cmd(usalp));
1272 }
1273
1274 int
1275 scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background)
1276 {
1277         register struct usal_cmd        *scmd = usalp->scmd;
1278         int progress=0, ret=-1, pid=-1;
1279         unsigned char sense_table[18];
1280         int i;
1281         
1282         printf("scsi_format: preparing\n");
1283
1284         fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
1285         scmd->addr = addr;
1286         scmd->size = size;
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;
1294
1295         usalp->cmdname = "format unit";
1296
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;
1301         if (background) {
1302                 if ((pid=fork()) == (pid_t)-1)
1303                         perror ("- [unable to fork()]");
1304                 else {
1305                         if (!pid) {
1306                             while (1) {
1307                                 if (test_unit_ready(usalp) >= 0)
1308                                     break;
1309                                 sleep(1);
1310                             }
1311                             return ret;
1312                         }
1313                 }
1314         }
1315         printf("Formating in progress: 0.00 %% done.");
1316         sleep(20);
1317         i = 0;
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);
1323                 usleep(100000);
1324                 i++;
1325                 /*for (i=0; i < 18; i++) {
1326                     printf("%d ", sense_table[i]);
1327                 }*/
1328         }
1329         sleep(10);
1330         printf("\rFormating in progress: 100.00 %% done.        \n");
1331         if (pid) exit (0);
1332         return ret;
1333 }
1334
1335 /*
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.
1339  */
1340 static BOOL     is_atapi;
1341
1342 BOOL
1343 allow_atapi(SCSI *usalp, BOOL new)
1344 {
1345         BOOL    old = is_atapi;
1346         Uchar   mode[256];
1347
1348         if (new == old)
1349                 return (old);
1350
1351         usalp->silent++;
1352         /*
1353          * If a bad drive has been reset before, we may need to fire up two
1354          * test unit ready commands to clear status.
1355          */
1356         (void) unit_ready(usalp);
1357         if (new &&
1358             mode_sense_g1(usalp, mode, 8, 0x3F, 0) < 0) {       /* All pages current */
1359                 new = FALSE;
1360         }
1361         usalp->silent--;
1362
1363         is_atapi = new;
1364         return (old);
1365 }
1366
1367 int
1368 mode_select(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1369 {
1370         if (is_atapi)
1371                 return (mode_select_sg0(usalp, dp, cnt, smp, pf));
1372         return (mode_select_g0(usalp, dp, cnt, smp, pf));
1373 }
1374
1375 int
1376 mode_sense(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1377 {
1378         if (is_atapi)
1379                 return (mode_sense_sg0(usalp, dp, cnt, page, pcf));
1380         return (mode_sense_g0(usalp, dp, cnt, page, pcf));
1381 }
1382
1383 /*
1384  * Simulate mode select g0 with mode select g1.
1385  */
1386 int
1387 mode_select_sg0(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1388 {
1389         Uchar   xmode[256+4];
1390         int     amt = cnt;
1391
1392         if (amt < 1 || amt > 255) {
1393                 /* XXX clear SCSI error codes ??? */
1394                 return (-1);
1395         }
1396
1397         if (amt < 4) {          /* Data length. medium type & VU */
1398                 amt += 1;
1399         } else {
1400                 amt += 4;
1401                 movebytes(&dp[4], &xmode[8], cnt-4);
1402         }
1403         xmode[0] = 0;
1404         xmode[1] = 0;
1405         xmode[2] = dp[1];
1406         xmode[3] = dp[2];
1407         xmode[4] = 0;
1408         xmode[5] = 0;
1409         i_to_2_byte(&xmode[6], (unsigned int)dp[3]);
1410
1411         if (usalp->verbose) usal_prbytes("Mode Parameters (un-converted)", dp, cnt);
1412
1413         return (mode_select_g1(usalp, xmode, amt, smp, pf));
1414 }
1415
1416 /*
1417  * Simulate mode sense g0 with mode sense g1.
1418  */
1419 int
1420 mode_sense_sg0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1421 {
1422         Uchar   xmode[256+4];
1423         int     amt = cnt;
1424         int     len;
1425
1426         if (amt < 1 || amt > 255) {
1427                 /* XXX clear SCSI error codes ??? */
1428                 return (-1);
1429         }
1430
1431         fillbytes((caddr_t)xmode, sizeof (xmode), '\0');
1432         if (amt < 4) {          /* Data length. medium type & VU */
1433                 amt += 1;
1434         } else {
1435                 amt += 4;
1436         }
1437         if (mode_sense_g1(usalp, xmode, amt, page, pcf) < 0)
1438                 return (-1);
1439
1440         amt = cnt - usal_getresid(usalp);
1441 /*
1442  * For tests: Solaris 8 & LG CD-ROM always returns resid == amt
1443  */
1444 /*      amt = cnt;*/
1445         if (amt > 4)
1446                 movebytes(&xmode[8], &dp[4], amt-4);
1447         len = a_to_u_2_byte(xmode);
1448         if (len == 0) {
1449                 dp[0] = 0;
1450         } else if (len < 6) {
1451                 if (len > 2)
1452                         len = 2;
1453                 dp[0] = len;
1454         } else {
1455                 dp[0] = len - 3;
1456         }
1457         dp[1] = xmode[2];
1458         dp[2] = xmode[3];
1459         len = a_to_u_2_byte(&xmode[6]);
1460         dp[3] = len;
1461
1462         if (usalp->verbose) usal_prbytes("Mode Sense Data (converted)", dp, amt);
1463         return (0);
1464 }
1465
1466 int
1467 mode_select_g0(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1468 {
1469         register struct usal_cmd        *scmd = usalp->scmd;
1470
1471         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1472         scmd->addr = (caddr_t)dp;
1473         scmd->size = cnt;
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;
1481
1482         if (usalp->verbose) {
1483                 fprintf(stderr, "%s ", smp?"Save":"Set ");
1484                 usal_prbytes("Mode Parameters", dp, cnt);
1485         }
1486
1487         usalp->cmdname = "mode select g0";
1488
1489         return (usal_cmd(usalp));
1490 }
1491
1492 int
1493 mode_select_g1(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
1494 {
1495         register struct usal_cmd        *scmd = usalp->scmd;
1496
1497         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1498         scmd->addr = (caddr_t)dp;
1499         scmd->size = cnt;
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);
1507
1508         if (usalp->verbose) {
1509                 printf("%s ", smp?"Save":"Set ");
1510                 usal_prbytes("Mode Parameters", dp, cnt);
1511         }
1512
1513         usalp->cmdname = "mode select g1";
1514
1515         return (usal_cmd(usalp));
1516 }
1517
1518 int
1519 mode_sense_g0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1520 {
1521         register struct usal_cmd        *scmd = usalp->scmd;
1522
1523         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1524         scmd->addr = (caddr_t)dp;
1525         scmd->size = 0xFF;
1526         scmd->size = cnt;
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);
1532 #ifdef  nonono
1533         scmd->cdb.g0_cdb.high_addr = 1<<4;      /* DBD Disable Block desc. */
1534 #endif
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;
1538
1539         usalp->cmdname = "mode sense g0";
1540
1541         if (usal_cmd(usalp) < 0)
1542                 return (-1);
1543         if (usalp->verbose) usal_prbytes("Mode Sense Data", dp, cnt - usal_getresid(usalp));
1544         return (0);
1545 }
1546
1547 int
1548 mode_sense_g1(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
1549 {
1550         register struct usal_cmd        *scmd = usalp->scmd;
1551
1552         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
1553         scmd->addr = (caddr_t)dp;
1554         scmd->size = cnt;
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);
1560 #ifdef  nonono
1561         scmd->cdb.g0_cdb.high_addr = 1<<4;      /* DBD Disable Block desc. */
1562 #endif
1563         scmd->cdb.g1_cdb.addr[0] = (page&0x3F) | ((pcf<<6)&0xC0);
1564         g1_cdblen(&scmd->cdb.g1_cdb, cnt);
1565
1566         usalp->cmdname = "mode sense g1";
1567
1568         if (usal_cmd(usalp) < 0)
1569                 return (-1);
1570         if (usalp->verbose) usal_prbytes("Mode Sense Data", dp, cnt - usal_getresid(usalp));
1571         return (0);
1572 }
1573
1574 struct trackdesc {
1575         Uchar   res0;
1576
1577 #if defined(_BIT_FIELDS_LTOH)           /* Intel byteorder */
1578         Ucbit   control         : 4;
1579         Ucbit   adr             : 4;
1580 #else                                   /* Motorola byteorder */
1581         Ucbit   adr             : 4;
1582         Ucbit   control         : 4;
1583 #endif
1584
1585         Uchar   track;
1586         Uchar   res3;
1587         Uchar   addr[4];
1588 };
1589
1590 struct diskinfo {
1591         struct tocheader        hd;
1592         struct trackdesc        desc[1];
1593 };
1594
1595 struct siheader {
1596         Uchar   len[2];
1597         Uchar   finished;
1598         Uchar   unfinished;
1599 };
1600
1601 struct sidesc {
1602         Uchar   sess_number;
1603         Uchar   res1;
1604         Uchar   track;
1605         Uchar   res3;
1606         Uchar   addr[4];
1607 };
1608
1609 struct sinfo {
1610         struct siheader hd;
1611         struct sidesc   desc[1];
1612 };
1613
1614 struct trackheader {
1615         Uchar   mode;
1616         Uchar   res[3];
1617         Uchar   addr[4];
1618 };
1619 #define TRM_ZERO        0
1620 #define TRM_USER_ECC    1       /* 2048 bytes user data + 288 Bytes ECC/EDC */
1621 #define TRM_USER        2       /* All user data (2336 bytes) */
1622
1623
1624 int
1625 read_tochdr(SCSI *usalp, cdr_t *dp, int *fp, int *lp)
1626 {
1627         struct  tocheader *tp;
1628         char    xb[256];
1629         int     len;
1630
1631         tp = (struct tocheader *)xb;
1632
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");
1637                 return (-1);
1638         }
1639         len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
1640         if (len >= 4) {
1641                 if (fp)
1642                         *fp = tp->first;
1643                 if (lp)
1644                         *lp = tp->last;
1645                 return (0);
1646         }
1647         return (-1);
1648 }
1649
1650 int
1651 read_cdtext(SCSI *usalp)
1652 {
1653         struct  tocheader *tp;
1654         char    xb[256];
1655         int     len;
1656         char    xxb[10000];
1657
1658         tp = (struct tocheader *)xb;
1659
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");
1664                 return (-1);
1665         }
1666         len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
1667         printf("CD-Text len: %d\n", len);
1668
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");
1672                 return (-1);
1673         }
1674         {
1675                 FILE    *f = fileopen("cdtext.dat", "wctb");
1676                 filewrite(f, xxb, len);
1677         }
1678         return (0);
1679 }
1680
1681 int
1682 read_trackinfo(SCSI *usalp, int track, long *offp, struct msf *msfp, int *adrp, 
1683                                         int *controlp, int *modep)
1684 {
1685         struct  diskinfo *dp;
1686         char    xb[256];
1687         int     len;
1688
1689         dp = (struct diskinfo *)xb;
1690
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");
1695                 return (-1);
1696         }
1697         len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
1698         if (len <  (int)sizeof (struct diskinfo))
1699                 return (-1);
1700
1701         if (offp)
1702                 *offp = a_to_4_byte(dp->desc[0].addr);
1703         if (adrp)
1704                 *adrp = dp->desc[0].adr;
1705         if (controlp)
1706                 *controlp = dp->desc[0].control;
1707
1708         if (msfp) {
1709                 usalp->silent++;
1710                 if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 1, FMT_TOC)
1711                                                                         >= 0) {
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)
1716                                                                         >= 0) {
1717                         /*
1718                          * Some drives (e.g. the Philips CDD-522) don't support
1719                          * to read the TOC in MSF mode.
1720                          */
1721                         long off = a_to_4_byte(dp->desc[0].addr);
1722
1723                         lba_to_msf(off, msfp);
1724                 } else {
1725                         msfp->msf_min = 0;
1726                         msfp->msf_sec = 0;
1727                         msfp->msf_frame = 0;
1728                 }
1729                 usalp->silent--;
1730         }
1731
1732         if (modep == NULL)
1733                 return (0);
1734
1735         if (track == 0xAA) {
1736                 *modep = -1;
1737                 return (0);
1738         }
1739
1740         fillbytes((caddr_t)xb, sizeof (xb), '\0');
1741
1742         usalp->silent++;
1743         if (read_header(usalp, xb, *offp, 8, 0) >= 0) {
1744                 *modep = xb[0];
1745         } else if (read_track_info_philips(usalp, xb, track, 14) >= 0) {
1746                 *modep = xb[0xb] & 0xF;
1747         } else {
1748                 *modep = -1;
1749         }
1750         usalp->silent--;
1751         return (0);
1752 }
1753
1754 int
1755 read_B0(SCSI *usalp, BOOL isbcd, long *b0p, long *lop)
1756 {
1757         struct  fdiskinfo *dp;
1758         struct  ftrackdesc *tp;
1759         char    xb[8192];
1760         char    *pe;
1761         int     len;
1762         long    l;
1763
1764         dp = (struct fdiskinfo *)xb;
1765
1766         fillbytes((caddr_t)xb, sizeof (xb), '\0');
1767         if (read_toc_philips(usalp, xb, 1, sizeof (struct tocheader), 0, FMT_FULLTOC) < 0) {
1768                 return (-1);
1769         }
1770         len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
1771         if (len <  (int)sizeof (struct fdiskinfo))
1772                 return (-1);
1773         if (read_toc_philips(usalp, xb, 1, len, 0, FMT_FULLTOC) < 0) {
1774                 return (-1);
1775         }
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);
1780
1781                 tp = &dp->desc[0];
1782                 pe = &xb[len];
1783
1784                 while ((char *)tp < pe) {
1785                         usal_prbytes("ENT: ", (Uchar *)tp, 11);
1786                         tp++;
1787                 }
1788         }
1789         tp = &dp->desc[0];
1790         pe = &xb[len];
1791
1792         for (; (char *)tp < pe; tp++) {
1793                 if (tp->sess_number != dp->hd.last)
1794                         continue;
1795                 if (tp->point != 0xB0)
1796                         continue;
1797                 if (usalp->verbose)
1798                         usal_prbytes("B0: ", (Uchar *)tp, 11);
1799                 if (isbcd) {
1800                         l = msf_to_lba(from_bcd(tp->amin),
1801                                 from_bcd(tp->asec),
1802                                 from_bcd(tp->aframe), TRUE);
1803                 } else {
1804                         l = msf_to_lba(tp->amin,
1805                                 tp->asec,
1806                                 tp->aframe, TRUE);
1807                 }
1808                 if (b0p)
1809                         *b0p = l;
1810
1811                 if (usalp->verbose)
1812                         printf("B0 start: %ld\n", l);
1813
1814                 if (isbcd) {
1815                         l = msf_to_lba(from_bcd(tp->pmin),
1816                                 from_bcd(tp->psec),
1817                                 from_bcd(tp->pframe), TRUE);
1818                 } else {
1819                         l = msf_to_lba(tp->pmin,
1820                                 tp->psec,
1821                                 tp->pframe, TRUE);
1822                 }
1823
1824                 if (usalp->verbose)
1825                         printf("B0 lout: %ld\n", l);
1826                 if (lop)
1827                         *lop = l;
1828                 return (0);
1829         }
1830         return (-1);
1831 }
1832
1833
1834 /*
1835  * Return address of first track in last session (SCSI-3/mmc version).
1836  */
1837 int
1838 read_session_offset(SCSI *usalp, long *offp)
1839 {
1840         struct  diskinfo *dp;
1841         char    xb[256];
1842         int     len;
1843
1844         dp = (struct diskinfo *)xb;
1845
1846         fillbytes((caddr_t)xb, sizeof (xb), '\0');
1847         if (read_toc(usalp, (caddr_t)xb, 0, sizeof (struct tocheader), 0, FMT_SINFO) < 0)
1848                 return (-1);
1849
1850         if (usalp->verbose)
1851                 usal_prbytes("tocheader: ",
1852                 (Uchar *)xb, sizeof (struct tocheader) - usal_getresid(usalp));
1853
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");
1857                 return (-1);
1858         }
1859         if (read_toc(usalp, (caddr_t)xb, 0, len, 0, FMT_SINFO) < 0)
1860                 return (-1);
1861
1862         if (usalp->verbose)
1863                 usal_prbytes("tocheader: ",
1864                         (Uchar *)xb, len - usal_getresid(usalp));
1865
1866         dp = (struct diskinfo *)xb;
1867         if (offp)
1868                 *offp = a_to_u_4_byte(dp->desc[0].addr);
1869         return (0);
1870 }
1871
1872 /*
1873  * Return address of first track in last session (pre SCSI-3 version).
1874  */
1875 int
1876 read_session_offset_philips(SCSI *usalp, long *offp)
1877 {
1878         struct  sinfo *sp;
1879         char    xb[256];
1880         int     len;
1881
1882         sp = (struct sinfo *)xb;
1883
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)
1886                 return (-1);
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");
1890                 return (-1);
1891         }
1892         if (read_toc_philips(usalp, (caddr_t)xb, 0, len, 0, FMT_SINFO) < 0)
1893                 return (-1);
1894         /*
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
1899          * as in SCSI-3
1900          * In all cases the lowest session number is set to 1.
1901          */
1902         sp = (struct sinfo *)xb;
1903         if (offp)
1904                 *offp = a_to_u_4_byte(sp->desc[sp->hd.finished-1].addr);
1905         return (0);
1906 }
1907
1908 int
1909 sense_secsize(SCSI *usalp, int current)
1910 {
1911         Uchar   mode[0x100];
1912         Uchar   *p;
1913         Uchar   *ep;
1914         int     len;
1915         int     secsize = -1;
1916
1917         usalp->silent++;
1918         (void) unit_ready(usalp);
1919         usalp->silent--;
1920
1921         /* XXX Quick and dirty, musz verallgemeinert werden !!! */
1922
1923         fillbytes(mode, sizeof (mode), '\0');
1924         usalp->silent++;
1925
1926         len =   sizeof (struct scsi_mode_header) +
1927                 sizeof (struct scsi_mode_blockdesc);
1928         /*
1929          * Wenn wir hier get_mode_params() nehmen bekommen wir die Warnung:
1930          * Warning: controller returns wrong page 1 for All pages page (3F).
1931          */
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) */
1935                         usalp->silent--;
1936                         return (-1);
1937                 }
1938         }
1939         if (mode[3] == 8) {
1940                 if (usalp->debug) {
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]));
1944                 }
1945                 secsize = a_to_u_3_byte(&mode[9]);
1946         }
1947         fillbytes(mode, sizeof (mode), '\0');
1948         /*
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.
1953          */
1954         if (usalp->debug &&
1955             mode_sense(usalp, mode, 0xFE, 0x3F, current?0:2) >= 0) {    /* All Pages */
1956
1957                 ep = mode+mode[0];      /* Points to last byte of data */
1958                 p = &mode[4];
1959                 p += mode[3];
1960                 printf("Pages: ");
1961                 while (p < ep) {
1962                         printf("0x%X ", *p&0x3F);
1963                         p += p[1]+2;
1964                 }
1965                 printf("\n");
1966         }
1967         usalp->silent--;
1968
1969         return (secsize);
1970 }
1971
1972 int
1973 select_secsize(SCSI *usalp, int secsize)
1974 {
1975         struct scsi_mode_data md;
1976         int     count = sizeof (struct scsi_mode_header) +
1977                         sizeof (struct scsi_mode_blockdesc);
1978
1979         (void) test_unit_ready(usalp);  /* clear any error situation */
1980
1981         fillbytes((caddr_t)&md, sizeof (md), '\0');
1982         md.header.blockdesc_len = 8;
1983         i_to_3_byte(md.blockdesc.lblen, secsize);
1984
1985         return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
1986 }
1987
1988 BOOL
1989 is_cddrive(SCSI *usalp)
1990 {
1991         return (usalp->inq->type == INQ_ROMD || usalp->inq->type == INQ_WORM);
1992 }
1993
1994 BOOL
1995 is_unknown_dev(SCSI *usalp)
1996 {
1997         return (usalp->dev == DEV_UNKNOWN);
1998 }
1999
2000 #ifndef DEBUG
2001 #define DEBUG
2002 #endif
2003 #ifdef  DEBUG
2004
2005 int
2006 read_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt)
2007 {
2008         if (addr <= G0_MAXADDR && cnt < 256 && !is_atapi)
2009                 return (read_g0(usalp, bp, addr, cnt));
2010         else
2011                 return (read_g1(usalp, bp, addr, cnt));
2012 }
2013
2014 int
2015 read_g0(SCSI *usalp, caddr_t bp, long addr, int cnt)
2016 {
2017         register struct usal_cmd        *scmd = usalp->scmd;
2018
2019         if (usalp->cap->c_bsize <= 0)
2020                 raisecond("capacity_not_set", 0L);
2021
2022         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2023         scmd->addr = bp;
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;*/
2033
2034         usalp->cmdname = "read_g0";
2035
2036         return (usal_cmd(usalp));
2037 }
2038
2039 int
2040 read_g1(SCSI *usalp, caddr_t bp, long addr, int cnt)
2041 {
2042         register struct usal_cmd        *scmd = usalp->scmd;
2043
2044         if (usalp->cap->c_bsize <= 0)
2045                 raisecond("capacity_not_set", 0L);
2046
2047         fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
2048         scmd->addr = bp;
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);
2057
2058         usalp->cmdname = "read_g1";
2059
2060         return (usal_cmd(usalp));
2061 }
2062 #endif  /* DEBUG */
2063
2064 BOOL
2065 getdev(SCSI *usalp, BOOL print)
2066 {
2067                 BOOL    got_inquiry = TRUE;
2068                 char    vendor_info[8+1];
2069                 char    prod_ident[16+1];
2070                 char    prod_revision[4+1];
2071                 int     inq_len = 0;
2072         register struct usal_cmd        *scmd = usalp->scmd;
2073         register struct scsi_inquiry *inq = usalp->inq;
2074
2075
2076         fillbytes((caddr_t)inq, sizeof (*inq), '\0');
2077         usalp->dev = DEV_UNKNOWN;
2078         usalp->silent++;
2079         (void) unit_ready(usalp);
2080         if (scmd->error >= SCG_FATAL &&
2081                                 !(scmd->scb.chk && scmd->sense_count > 0)) {
2082                 usalp->silent--;
2083                 return (FALSE);
2084         }
2085
2086
2087 /*      if (scmd->error < SCG_FATAL || scmd->scb.chk && scmd->sense_count > 0){*/
2088
2089         if (inquiry(usalp, (caddr_t)inq, sizeof (*inq)) < 0) {
2090                 got_inquiry = FALSE;
2091         } else {
2092                 inq_len = sizeof (*inq) - usal_getresid(usalp);
2093         }
2094         if (!got_inquiry) {
2095                 if (usalp->verbose) {
2096                         printf(
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);
2100                 }
2101                         /*
2102                          * Folgende Kontroller kennen das Kommando
2103                          * INQUIRY nicht:
2104                          *
2105                          * ADAPTEC      ACB-4000, ACB-4010, ACB 4070
2106                          * SYSGEN       SC4000
2107                          *
2108                          * Leider reagieren ACB40X0 und ACB5500 identisch
2109                          * wenn drive not ready (code == not ready),
2110                          * sie sind dann nicht zu unterscheiden.
2111                          */
2112
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();*/
2119                         } else {
2120                                 usalp->dev = DEV_SC4000;
2121                                 inq->type = INQ_SEQD;
2122                                 inq->removable = 1;
2123                         }
2124                 }
2125         } else if (usalp->verbose) {
2126                 int     i;
2127                 int     len = inq->add_len + 5;
2128                 Uchar   ibuf[256+5];
2129                 Uchar   *ip = (Uchar *)inq;
2130                 Uchar   c;
2131
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);
2135                         ip = ibuf;
2136                 } else {
2137                         len = sizeof (*inq);
2138                 }
2139                 printf("Inquiry Data   : ");
2140                 for (i = 0; i < len; i++) {
2141                         c = ip[i];
2142                         if (c >= ' ' && c < 0177)
2143                                 printf("%c", c);
2144                         else
2145                                 printf(".");
2146                 }
2147                 printf("\n");
2148         }
2149
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));
2153
2154         vendor_info[sizeof (inq->vendor_info)] = '\0';
2155         prod_ident[sizeof (inq->prod_ident)] = '\0';
2156         prod_revision[sizeof (inq->prod_revision)] = '\0';
2157
2158         switch (inq->type) {
2159
2160         case INQ_DASD:
2161                 if (inq->add_len == 0 && inq->vendor_info[0] != '\0') {
2162                         Uchar   *p;
2163                         /*
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.
2168                          */
2169                         if (inq_len >= 36)
2170                                 inq->add_len = 31;
2171
2172                         for (p = (Uchar *)&inq->vendor_info[0];
2173                                         p < (Uchar *)&inq->prod_revision[4];
2174                                                                         p++) {
2175                                 if (*p < 0x20 || *p > 0x7E) {
2176                                         inq->add_len = 0;
2177                                         break;
2178                                 }
2179                         }
2180                 }
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");
2186
2187                         } else switch (usalp->dev) {
2188
2189                                 case DEV_ACB40X0:
2190                                         strcpy(inq->vendor_info,
2191                                                         "ADAPTEC ACB-40X0        FAKE");
2192                                         break;
2193                                 case DEV_ACB4000:
2194                                         strcpy(inq->vendor_info,
2195                                                         "ADAPTEC ACB-4000        FAKE");
2196                                         break;
2197                                 case DEV_ACB4010:
2198                                         strcpy(inq->vendor_info,
2199                                                         "ADAPTEC ACB-4010        FAKE");
2200                                         break;
2201                                 case DEV_ACB4070:
2202                                         strcpy(inq->vendor_info,
2203                                                         "ADAPTEC ACB-4070        FAKE");
2204                                         break;
2205                         }
2206                 } else if (inq->add_len < 31) {
2207                         usalp->dev = DEV_NON_CCS_DSK;
2208
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;
2214                         else
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;
2221                         else
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;
2226                 } else {
2227                         usalp->dev = DEV_CCS_GENDISK;
2228                 }
2229                 break;
2230
2231         case INQ_SEQD:
2232                 if (usalp->dev == DEV_SC4000) {
2233                         strcpy(inq->vendor_info,
2234                                 "SYSGEN  SC4000          FAKE");
2235                 } else if (inq->add_len == 0 &&
2236                                         inq->removable &&
2237                                                 inq->ansi_version == 1) {
2238                         usalp->dev = DEV_MT02;
2239                         strcpy(inq->vendor_info,
2240                                 "EMULEX  MT02            FAKE");
2241                 }
2242                 break;
2243
2244 /*      case INQ_OPTD:*/
2245         case INQ_ROMD:
2246         case INQ_WORM:
2247                 if (strbeg("RXT-800S", prod_ident))
2248                         usalp->dev = DEV_RXT800S;
2249
2250                 /*
2251                  * Start of CD-Recorders:
2252                  */
2253                 if (strbeg("ACER", vendor_info)) {
2254                         if (strbeg("CR-4020C", prod_ident))
2255                                 usalp->dev = DEV_RICOH_RO_1420C;
2256
2257                 } else if (strbeg("CREATIVE", vendor_info)) {
2258                         if (strbeg("CDR2000", prod_ident))
2259                                 usalp->dev = DEV_RICOH_RO_1060C;
2260
2261                 } else if (strbeg("GRUNDIG", vendor_info)) {
2262                         if (strbeg("CDR100IPW", prod_ident))
2263                                 usalp->dev = DEV_CDD_2000;
2264
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;
2272
2273                 } else if (strbeg("MITSBISH", vendor_info)) {
2274
2275 #ifdef  XXXX_REALLY
2276                         /* It's MMC compliant */
2277                         if (strbeg("CDRW226", prod_ident))
2278                                 usalp->dev = DEV_MMC_CDRW;
2279 #else
2280                         /* EMPTY */
2281 #endif
2282
2283                 } else if (strbeg("MITSUMI", vendor_info)) {
2284                         /* Don't know any product string */
2285                         usalp->dev = DEV_CDD_522;
2286
2287                 } else if (strbeg("OPTIMA", vendor_info)) {
2288                         if (strbeg("CD-R 650", prod_ident))
2289                                 usalp->dev = DEV_SONY_CDU_924;
2290
2291                 } else if (strbeg("PHILIPS", vendor_info) ||
2292                                 strbeg("IMS", vendor_info) ||
2293                                 strbeg("KODAK", vendor_info) ||
2294                                 strbeg("HP", vendor_info)) {
2295
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;
2302
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;
2311
2312                         if (strbeg("CDD20", prod_ident))
2313                                 usalp->dev = DEV_CDD_2000;
2314                         if (strbeg("CDD26", prod_ident))
2315                                 usalp->dev = DEV_CDD_2600;
2316
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;
2321
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;
2331
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;
2339
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;
2345
2346                 } else if (strbeg("PLEXTOR", vendor_info)) {
2347                         if (strbeg("CD-R   PX-R24CS", prod_ident))
2348                                 usalp->dev = DEV_RICOH_RO_1420C;
2349
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;
2355
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;
2366
2367                 } else if (strbeg("SANYO", vendor_info)) {
2368                         if (strbeg("CD-WO CRD-R24S", prod_ident))
2369                                 usalp->dev = DEV_CDD_521;
2370
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;
2375
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;
2380
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;
2385
2386                 } else if (strbeg("T.YUDEN", vendor_info)) {
2387                         if (strbeg("CD-WO EW-50", prod_ident))
2388                                 usalp->dev = DEV_TYUDEN_EW50;
2389
2390                 } else if (strbeg("WPI", vendor_info)) {        /* Wearnes */
2391                         if (strbeg("CDR-632P", prod_ident))
2392                                 usalp->dev = DEV_CDD_2600;
2393
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;
2401
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;
2407                 }
2408                 if (usalp->dev == DEV_UNKNOWN) {
2409                         /*
2410                          * We do not have Manufacturer strings for
2411                          * the following drives.
2412                          */
2413                         if (strbeg("CDS615E", prod_ident))      /* Olympus */
2414                                 usalp->dev = DEV_SONY_CDU_924;
2415                 }
2416                 if (usalp->dev == DEV_UNKNOWN && inq->type == INQ_ROMD) {
2417                         BOOL    cdrr     = FALSE;
2418                         BOOL    cdwr     = FALSE;
2419                         BOOL    cdrrw    = FALSE;
2420                         BOOL    cdwrw    = FALSE;
2421                         BOOL    dvd      = FALSE;
2422                         BOOL    dvdwr    = FALSE;
2423
2424                         usalp->dev = DEV_CDROM;
2425
2426                         if (mmc_check(usalp, &cdrr, &cdwr, &cdrrw, &cdwrw,
2427                                                                 &dvd, &dvdwr))
2428                                 usalp->dev = DEV_MMC_CDROM;
2429                         if (cdwr)
2430                                 usalp->dev = DEV_MMC_CDR;
2431                         if (cdwrw)
2432                                 usalp->dev = DEV_MMC_CDRW;
2433                         if (dvd)
2434                                 usalp->dev = DEV_MMC_DVD;
2435                         if (dvdwr)
2436                                 usalp->dev = DEV_MMC_DVD_WR;
2437                 }
2438                 break;
2439
2440         case INQ_PROCD:
2441                 if (strbeg("BERTHOLD", vendor_info)) {
2442                         if (strbeg("", prod_ident))
2443                                 usalp->dev = DEV_HRSCAN;
2444                 }
2445                 break;
2446
2447         case INQ_SCAN:
2448                 usalp->dev = DEV_MS300A;
2449                 break;
2450         }
2451         usalp->silent--;
2452         if (!print)
2453                 return (TRUE);
2454
2455         if (usalp->dev == DEV_UNKNOWN && !got_inquiry) {
2456 #ifdef  PRINT_INQ_ERR
2457                 usal_printerr(usalp);
2458 #endif
2459                 return (FALSE);
2460         }
2461
2462         printinq(usalp, stdout);
2463         return (TRUE);
2464 }
2465
2466 void
2467 printinq(SCSI *usalp, FILE *f)
2468 {
2469         register struct scsi_inquiry *inq = usalp->inq;
2470
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 ");
2486                 fprintf(f, "\n");
2487         }
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);
2495         }
2496 }
2497
2498 void
2499 printdev(SCSI *usalp)
2500 {
2501         printf("Device seems to be: ");
2502
2503         switch (usalp->dev) {
2504
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;
2523
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;
2545
2546         case DEV_PIONEER_DW_S114X: printf("Pioneer DW-S114X");  break;
2547         case DEV_PIONEER_DVDR_S101:printf("Pioneer DVD-R S101"); break;
2548
2549         default:                printf("Missing Entry for dev %d",
2550                                                 usalp->dev);    break;
2551
2552         }
2553         printf(".\n");
2554
2555 }
2556
2557 BOOL
2558 do_inquiry(SCSI *usalp, int print)
2559 {
2560         if (getdev(usalp, print)) {
2561                 if (print)
2562                         printdev(usalp);
2563                 return (TRUE);
2564         } else {
2565                 return (FALSE);
2566         }
2567 }
2568
2569 BOOL
2570 recovery_needed(SCSI *usalp, cdr_t *dp)
2571 {
2572                 int err;
2573         register struct usal_cmd        *scmd = usalp->scmd;
2574
2575         usalp->silent++;
2576         err = test_unit_ready(usalp);
2577         usalp->silent--;
2578
2579         if (err >= 0)
2580                 return (FALSE);
2581         else if (scmd->error >= SCG_FATAL)      /* nicht selektierbar */
2582                 return (FALSE);
2583
2584         if (scmd->sense.code < 0x70)            /* non extended Sense */
2585                 return (FALSE);
2586
2587                                                 /* XXX Old Philips code */
2588         return (((struct scsi_ext_sense *)&scmd->sense)->sense_code == 0xD0);
2589 }
2590
2591 int
2592 scsi_load(SCSI *usalp, cdr_t *dp)
2593 {
2594         int     key;
2595         int     code;
2596
2597         if ((dp->cdr_flags & CDR_CADDYLOAD) == 0) {
2598                 if (scsi_start_stop_unit(usalp, 1, 1, dp && (dp->cdr_cmdflags&F_IMMED)) >= 0)
2599                         return (0);
2600         }
2601
2602         if (wait_unit_ready(usalp, 60))
2603                 return (0);
2604
2605         key = usal_sense_key(usalp);
2606         code = usal_sense_code(usalp);
2607
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");
2612         }
2613         return (-1);
2614 }
2615
2616 int
2617 scsi_unload(SCSI *usalp, cdr_t *dp)
2618 {
2619         return (scsi_start_stop_unit(usalp, 0, 1, dp && (dp->cdr_cmdflags&F_IMMED)));
2620 }
2621
2622 int 
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 */)
2629 {
2630         return (write_xg1(usalp, bp, sectaddr, size, blocks));
2631 }
2632
2633 struct cd_mode_page_2A *
2634 mmc_cap(SCSI *usalp, Uchar *modep)
2635 {
2636         int     len;
2637         int     val;
2638         Uchar   mode[0x100];
2639         struct  cd_mode_page_2A *mp;
2640         struct  cd_mode_page_2A *mp2;
2641
2642
2643 retry:
2644         fillbytes((caddr_t)mode, sizeof (mode), '\0');
2645
2646         if (!get_mode_params(usalp, 0x2A, "CD capabilities",
2647                         mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
2648
2649                 if (usal_sense_key(usalp) == SC_NOT_READY) {
2650                         if (wait_unit_ready(usalp, 60))
2651                                 goto retry;
2652                 }
2653                 return (NULL);          /* Pre SCSI-3/mmc drive         */
2654         }
2655
2656         if (len == 0)                   /* Pre SCSI-3/mmc drive         */
2657                 return (NULL);
2658
2659         mp = (struct cd_mode_page_2A *)
2660                 (mode + sizeof (struct scsi_mode_header) +
2661                 ((struct scsi_mode_header *)mode)->blockdesc_len);
2662
2663         /*
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.
2667          */
2668         if (mp->p_len < 0x10)
2669                 return (NULL);
2670
2671         val = a_to_u_2_byte(mp->max_read_speed);
2672         if (val != 0 && val < 176)
2673                 return (NULL);
2674
2675         val = a_to_u_2_byte(mp->cur_read_speed);
2676         if (val != 0 && val < 176)
2677                 return (NULL);
2678
2679         len -= sizeof (struct scsi_mode_header) +
2680                 ((struct scsi_mode_header *)mode)->blockdesc_len;
2681         if (modep)
2682                 mp2 = (struct cd_mode_page_2A *)modep;
2683         else
2684                 mp2 = malloc(len);
2685         if (mp2)
2686                 movebytes(mp, mp2, len);
2687
2688         return (mp2);
2689 }
2690
2691 void
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 */)
2699 {
2700         BOOL    isdvd;                          /* Any DVD reader       */
2701         BOOL    isdvd_wr;                       /* DVD writer (R / RAM) */
2702         BOOL    iscd_wr;                        /* CD  writer           */
2703
2704         iscd_wr = (mp->cd_r_write != 0) ||      /* SCSI-3/mmc CD-R      */
2705                     (mp->cd_rw_write != 0);     /* SCSI-3/mmc CD-RW     */
2706
2707         if (cdrrp)
2708                 *cdrrp = (mp->cd_r_read != 0);  /* SCSI-3/mmc CD        */
2709         if (cdwrp)
2710                 *cdwrp = (mp->cd_r_write != 0); /* SCSI-3/mmc CD-R      */
2711
2712         if (cdrrwp)
2713                 *cdrrwp = (mp->cd_rw_read != 0); /* SCSI-3/mmc CD       */
2714         if (cdwrwp)
2715                 *cdwrwp = (mp->cd_rw_write != 0); /* SCSI-3/mmc CD-RW   */
2716
2717         isdvd =                                 /* SCSI-3/mmc2 DVD      */
2718                 (mp->dvd_ram_read + mp->dvd_r_read  +
2719                     mp->dvd_rom_read) != 0;
2720
2721         isdvd_wr =                              /* SCSI-3/mmc2 DVD writer*/
2722                 (mp->dvd_ram_write + mp->dvd_r_write) != 0;
2723
2724         if (dvdp)
2725                 *dvdp = isdvd;
2726         if (dvdwp)
2727                 *dvdwp = isdvd_wr;
2728 }
2729
2730 BOOL
2731 is_mmc(SCSI *usalp, BOOL *cdwp, BOOL *dvdwp)
2732 {
2733         BOOL    cdwr    = FALSE;
2734         BOOL    cdwrw   = FALSE;
2735
2736         if (cdwp)
2737                 *cdwp = FALSE;
2738         if (dvdwp)
2739                 *dvdwp = FALSE;
2740
2741         if (!mmc_check(usalp, NULL, &cdwr, NULL, &cdwrw, NULL, dvdwp))
2742                 return (FALSE);
2743
2744         if (cdwp)
2745                 *cdwp = cdwr | cdwrw;
2746
2747         return (TRUE);
2748 }
2749
2750 BOOL
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 */)
2758 {
2759         Uchar   mode[0x100];
2760         BOOL    was_atapi;
2761         struct  cd_mode_page_2A *mp;
2762
2763         if (usalp->inq->type != INQ_ROMD)
2764                 return (FALSE);
2765
2766         fillbytes((caddr_t)mode, sizeof (mode), '\0');
2767
2768         was_atapi = allow_atapi(usalp, TRUE);
2769         usalp->silent++;
2770         mp = mmc_cap(usalp, mode);
2771         usalp->silent--;
2772         allow_atapi(usalp, was_atapi);
2773         if (mp == NULL)
2774                 return (FALSE);
2775
2776         mmc_getval(mp, cdrrp, cdwrp, cdrrwp, cdwrwp, dvdp, dvdwp);
2777
2778         return (TRUE);                  /* Generic SCSI-3/mmc CD        */
2779 }
2780
2781 static void
2782 print_speed(char *fmt, int val)
2783 {
2784         printf("  %s: %5d kB/s", fmt, val);
2785         printf(" (CD %3ux,", val/176);
2786         printf(" DVD %2ux)\n", val/1385);
2787 }
2788
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)
2793
2794 void
2795 print_capabilities(SCSI *usalp)
2796 {
2797         BOOL    was_atapi;
2798         Uchar   mode[0x100];
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)"};
2805
2806
2807         if (usalp->inq->type != INQ_ROMD)
2808                 return;
2809
2810         fillbytes((caddr_t)mode, sizeof (mode), '\0');
2811
2812         was_atapi = allow_atapi(usalp, TRUE);   /* Try to switch to 10 byte mode cmds */
2813         usalp->silent++;
2814         mp = mmc_cap(usalp, mode);
2815         usalp->silent--;
2816         allow_atapi(usalp, was_atapi);
2817         if (mp == NULL)
2818                 return;
2819
2820         printf("\nDrive capabilities, per");
2821         if (mp->p_len >= 28)
2822                 printf(" MMC-3");
2823         else if (mp->p_len >= 24)
2824                 printf(" MMC-2");
2825         else
2826                 printf(" MMC");
2827         printf(" page 2A:\n\n");
2828
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);
2839         printf("\n");
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);
2857         printf("\n");
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]);
2870                 }
2871         }
2872         printf("\n");
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);
2881         printf("\n");
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));
2887         else
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]);
2891         }
2892         VAL("Buffer size in KB", mp->buffer_size);
2893
2894         if (mp->p_len >= 24) {
2895                 VAL("Copy management revision supported", mp->copy_man_rev);
2896         }
2897
2898         if (mp->p_len >= 28) {
2899                 struct cd_wr_speed_performance *pp;
2900                 Uint    ndesc;
2901                 Uint    i;
2902                 Uint    n;
2903
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);
2914                 }
2915         }
2916
2917         /* Generic SCSI-3/mmc CD        */
2918 }