summaryrefslogtreecommitdiff
path: root/wodim/scsi_cdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'wodim/scsi_cdr.c')
-rw-r--r--wodim/scsi_cdr.c2918
1 files changed, 2918 insertions, 0 deletions
diff --git a/wodim/scsi_cdr.c b/wodim/scsi_cdr.c
new file mode 100644
index 0000000..fbb8270
--- /dev/null
+++ b/wodim/scsi_cdr.c
@@ -0,0 +1,2918 @@
+/*
+ * This file has been modified for the cdrkit suite.
+ *
+ * The behaviour and appearence of the program code below can differ to a major
+ * extent from the version distributed by the original author(s).
+ *
+ * For details, see Changelog file distributed with the cdrkit package. If you
+ * received this file from another source then ask the distributing person for
+ * a log of modifications.
+ *
+ */
+
+/* @(#)scsi_cdr.c 1.137 04/05/25 Copyright 1995-2004 J. Schilling */
+/*
+ * SCSI command functions for cdrecord
+ * covering pre-MMC standard functions up to MMC-2
+ *
+ * Copyright (c) 1995-2004 J. Schilling
+ */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * NOTICE: The Philips CDD 521 has several firmware bugs.
+ * One of them is not to respond to a SCSI selection
+ * within 200ms if the general load on the
+ * SCSI bus is high. To deal with this problem
+ * most of the SCSI commands are send with the
+ * SCG_CMD_RETRY flag enabled.
+ */
+#include <mconfig.h>
+
+#include <stdio.h>
+#include <standard.h>
+#include <stdxlib.h>
+#include <unixstd.h>
+#include <fctldefs.h>
+#include <errno.h>
+#include <strdefs.h>
+#include <timedefs.h>
+
+#include <utypes.h>
+#include <btorder.h>
+#include <intcvt.h>
+#include <schily.h>
+
+#include <usal/usalcmd.h>
+#include <usal/scsidefs.h>
+#include <usal/scsireg.h>
+#include <usal/scsitransp.h>
+
+#include "scsimmc.h"
+#include "wodim.h"
+#include "scsi_scan.h"
+
+#define strbeg(s1, s2) (strstr((s2), (s1)) == (s2))
+
+BOOL unit_ready(SCSI *usalp);
+BOOL wait_unit_ready(SCSI *usalp, int secs);
+BOOL scsi_in_progress(SCSI *usalp);
+BOOL cdr_underrun(SCSI *usalp);
+int test_unit_ready(SCSI *usalp);
+int rezero_unit(SCSI *usalp);
+int request_sense(SCSI *usalp);
+int request_sense_b(SCSI *usalp, caddr_t bp, int cnt);
+int inquiry(SCSI *usalp, caddr_t, int);
+int read_capacity(SCSI *usalp);
+void print_capacity(SCSI *usalp, FILE *f);
+int scsi_load_unload(SCSI *usalp, int);
+int scsi_prevent_removal(SCSI *usalp, int);
+int scsi_start_stop_unit(SCSI *usalp, int, int, BOOL immed);
+int scsi_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl);
+int scsi_get_speed(SCSI *usalp, int *readspeedp, int *writespeedp);
+int qic02(SCSI *usalp, int);
+int write_xscsi(SCSI *usalp, caddr_t, long, long, int);
+int write_xg0(SCSI *usalp, caddr_t, long, long, int);
+int write_xg1(SCSI *usalp, caddr_t, long, long, int);
+int write_xg5(SCSI *usalp, caddr_t, long, long, int);
+int seek_scsi(SCSI *usalp, long addr);
+int seek_g0(SCSI *usalp, long addr);
+int seek_g1(SCSI *usalp, long addr);
+int scsi_flush_cache(SCSI *usalp, BOOL immed);
+int read_buffer(SCSI *usalp, caddr_t bp, int cnt, int mode);
+int write_buffer(SCSI *usalp, char *buffer, long length, int mode,
+ int bufferid, long offset);
+int read_subchannel(SCSI *usalp, caddr_t bp, int track, int cnt, int msf,
+ int subq, int fmt);
+int read_toc(SCSI *usalp, caddr_t, int, int, int, int);
+int read_toc_philips(SCSI *usalp, caddr_t, int, int, int, int);
+int read_header(SCSI *usalp, caddr_t, long, int, int);
+int read_disk_info(SCSI *usalp, caddr_t, int);
+int read_track_info(SCSI *usalp, caddr_t, int type, int addr, int cnt);
+int read_rzone_info(SCSI *usalp, caddr_t bp, int cnt);
+int reserve_tr_rzone(SCSI *usalp, long size);
+int read_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int addr, int layer,
+ int fmt);
+int send_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int layer, int fmt);
+int send_opc(SCSI *usalp, caddr_t, int cnt, int doopc);
+int read_track_info_philips(SCSI *usalp, caddr_t, int, int);
+int scsi_close_tr_session(SCSI *usalp, int type, int track, BOOL immed);
+int read_master_cue(SCSI *usalp, caddr_t bp, int sheet, int cnt);
+int send_cue_sheet(SCSI *usalp, caddr_t bp, long size);
+int read_buff_cap(SCSI *usalp, long *, long *);
+int scsi_blank(SCSI *usalp, long addr, int blanktype, BOOL immed);
+int scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background);
+int scsi_set_streaming(SCSI *usalp, caddr_t addr, int size);
+BOOL allow_atapi(SCSI *usalp, BOOL new);
+int mode_select(SCSI *usalp, Uchar *, int, int, int);
+int mode_sense(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
+int mode_select_sg0(SCSI *usalp, Uchar *, int, int, int);
+int mode_sense_sg0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
+int mode_select_g0(SCSI *usalp, Uchar *, int, int, int);
+int mode_select_g1(SCSI *usalp, Uchar *, int, int, int);
+int mode_sense_g0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
+int mode_sense_g1(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf);
+int read_tochdr(SCSI *usalp, cdr_t *, int *, int *);
+int read_cdtext(SCSI *usalp);
+int read_trackinfo(SCSI *usalp, int, long *, struct msf *, int *, int *,
+ int *);
+int read_B0(SCSI *usalp, BOOL isbcd, long *b0p, long *lop);
+int read_session_offset(SCSI *usalp, long *);
+int read_session_offset_philips(SCSI *usalp, long *);
+int sense_secsize(SCSI *usalp, int current);
+int select_secsize(SCSI *usalp, int);
+BOOL is_cddrive(SCSI *usalp);
+BOOL is_unknown_dev(SCSI *usalp);
+int read_scsi(SCSI *usalp, caddr_t, long, int);
+int read_g0(SCSI *usalp, caddr_t, long, int);
+int read_g1(SCSI *usalp, caddr_t, long, int);
+BOOL getdev(SCSI *usalp, BOOL);
+void printinq(SCSI *usalp, FILE *f);
+void printdev(SCSI *usalp);
+BOOL do_inquiry(SCSI *usalp, BOOL);
+BOOL recovery_needed(SCSI *usalp, cdr_t *);
+int scsi_load(SCSI *usalp, cdr_t *);
+int scsi_unload(SCSI *usalp, cdr_t *);
+int scsi_cdr_write(SCSI *usalp, caddr_t bp, long sectaddr, long size,
+ int blocks, BOOL islast);
+struct cd_mode_page_2A * mmc_cap(SCSI *usalp, Uchar *modep);
+void mmc_getval(struct cd_mode_page_2A *mp, BOOL *cdrrp, BOOL *cdwrp,
+ BOOL *cdrrwp, BOOL *cdwrwp, BOOL *dvdp, BOOL *dvdwp);
+BOOL is_mmc(SCSI *usalp, BOOL *cdwp, BOOL *dvdwp);
+BOOL mmc_check(SCSI *usalp, BOOL *cdrrp, BOOL *cdwrp, BOOL *cdrrwp,
+ BOOL *cdwrwp, BOOL *dvdp, BOOL *dvdwp);
+static void print_speed(char *fmt, int val);
+void print_capabilities(SCSI *usalp);
+
+BOOL
+unit_ready(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ if (test_unit_ready(usalp) >= 0) /* alles OK */
+ return (TRUE);
+ else if (scmd->error >= SCG_FATAL) /* nicht selektierbar */
+ return (FALSE);
+
+ if (usal_sense_key(usalp) == SC_UNIT_ATTENTION) {
+ if (test_unit_ready(usalp) >= 0) /* alles OK */
+ return (TRUE);
+ }
+ if ((usal_cmd_status(usalp) & ST_BUSY) != 0) {
+ /*
+ * Busy/reservation_conflict
+ */
+ usleep(500000);
+ if (test_unit_ready(usalp) >= 0) /* alles OK */
+ return (TRUE);
+ }
+ if (usal_sense_key(usalp) == -1) { /* non extended Sense */
+ if (usal_sense_code(usalp) == 4) /* NOT_READY */
+ return (FALSE);
+ return (TRUE);
+ }
+ /* FALSE wenn NOT_READY */
+ return (usal_sense_key(usalp) != SC_NOT_READY);
+}
+
+BOOL
+wait_unit_ready(SCSI *usalp, int secs)
+{
+ int i;
+ int c;
+ int k;
+ int ret;
+
+ usalp->silent++;
+ ret = test_unit_ready(usalp); /* eat up unit attention */
+ if (ret < 0)
+ ret = test_unit_ready(usalp); /* got power on condition? */
+ usalp->silent--;
+
+ if (ret >= 0) /* success that's enough */
+ return (TRUE);
+
+ usalp->silent++;
+ for (i = 0; i < secs && (ret = test_unit_ready(usalp)) < 0; i++) {
+ if (usalp->scmd->scb.busy != 0) {
+ sleep(1);
+ continue;
+ }
+ c = usal_sense_code(usalp);
+ k = usal_sense_key(usalp);
+ /*
+ * Abort quickly if it does not make sense to wait.
+ * 0x30 == Cannot read medium
+ * 0x3A == Medium not present
+ */
+ if ((k == SC_NOT_READY && (c == 0x3A || c == 0x30)) ||
+ (k == SC_MEDIUM_ERROR)) {
+ if (usalp->silent <= 1)
+ usal_printerr(usalp);
+ usalp->silent--;
+ return (FALSE);
+ }
+ sleep(1);
+ }
+ usalp->silent--;
+ if (ret < 0)
+ return (FALSE);
+ return (TRUE);
+}
+
+BOOL
+scsi_in_progress(SCSI *usalp)
+{
+ if (usal_sense_key(usalp) == SC_NOT_READY &&
+ /*
+ * Logigal unit not ready operation/long_write in progress
+ */
+ usal_sense_code(usalp) == 0x04 &&
+ (usal_sense_qual(usalp) == 0x04 || /* CyberDr. "format in progress"*/
+ usal_sense_qual(usalp) == 0x07 || /* "operation in progress" */
+ usal_sense_qual(usalp) == 0x08)) { /* "long write in progress" */
+ return (TRUE);
+ } else {
+ if (usalp->silent <= 1)
+ usal_printerr(usalp);
+ }
+ return (FALSE);
+}
+
+BOOL
+cdr_underrun(SCSI *usalp)
+{
+ if ((usal_sense_key(usalp) != SC_ILLEGAL_REQUEST &&
+ usal_sense_key(usalp) != SC_MEDIUM_ERROR))
+ return (FALSE);
+
+ if ((usal_sense_code(usalp) == 0x21 &&
+ (usal_sense_qual(usalp) == 0x00 || /* logical block address out of range */
+ usal_sense_qual(usalp) == 0x02)) || /* invalid address for write */
+
+ (usal_sense_code(usalp) == 0x0C &&
+ usal_sense_qual(usalp) == 0x09)) { /* write error - loss of streaming */
+ return (TRUE);
+ }
+ /*
+ * XXX Bei manchen Brennern kommt mach dem der Brennvorgang bereits
+ * XXX eine Weile gelaufen ist ein 5/24/0 Invalid field in CDB.
+ * XXX Daher sollte man testen ob schon geschrieben wurde...
+ */
+ return (FALSE);
+}
+
+int
+test_unit_ready(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)0;
+ scmd->size = 0;
+ scmd->flags = SCG_DISRE_ENA | (usalp->silent ? SCG_SILENT:0);
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+
+ usalp->cmdname = "test unit ready";
+
+ return (usal_cmd(usalp));
+}
+
+int
+rezero_unit(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)0;
+ scmd->size = 0;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_REZERO_UNIT;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+
+ usalp->cmdname = "rezero unit";
+
+ return (usal_cmd(usalp));
+}
+
+int
+request_sense(SCSI *usalp)
+{
+ char sensebuf[CCS_SENSE_LEN];
+ register struct usal_cmd *scmd = usalp->scmd;
+
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = sensebuf;
+ scmd->size = sizeof (sensebuf);
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.count = CCS_SENSE_LEN;
+
+ usalp->cmdname = "request_sense";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ usal_prsense((Uchar *)sensebuf, CCS_SENSE_LEN - usal_getresid(usalp));
+ return (0);
+}
+
+int
+request_sense_b(SCSI *usalp, caddr_t bp, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_REQUEST_SENSE;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.count = cnt;
+
+ usalp->cmdname = "request_sense";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+inquiry(SCSI *usalp, caddr_t bp, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes(bp, cnt, '\0');
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_INQUIRY;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.count = cnt;
+
+ usalp->cmdname = "inquiry";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ if (usalp->verbose)
+ usal_prbytes("Inquiry Data :", (Uchar *)bp, cnt - usal_getresid(usalp));
+ return (0);
+}
+
+int
+read_capacity(SCSI *usalp)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)usalp->cap;
+ scmd->size = sizeof (struct scsi_capacity);
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x25; /* Read Capacity */
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdblen(&scmd->cdb.g1_cdb, 0); /* Full Media */
+
+ usalp->cmdname = "read capacity";
+
+ if (usal_cmd(usalp) < 0) {
+ return (-1);
+ } else {
+ long cbsize;
+ long cbaddr;
+
+ /*
+ * c_bsize & c_baddr are signed Int32_t
+ * so we use signed int conversion here.
+ */
+ cbsize = a_to_4_byte(&usalp->cap->c_bsize);
+ cbaddr = a_to_4_byte(&usalp->cap->c_baddr);
+ usalp->cap->c_bsize = cbsize;
+ usalp->cap->c_baddr = cbaddr;
+ }
+ return (0);
+}
+
+void
+print_capacity(SCSI *usalp, FILE *f)
+{
+ long kb;
+ long mb;
+ long prmb;
+ double dkb;
+
+ dkb = (usalp->cap->c_baddr+1.0) * (usalp->cap->c_bsize/1024.0);
+ kb = dkb;
+ mb = dkb / 1024.0;
+ prmb = dkb / 1000.0 * 1.024;
+ fprintf(f, "Capacity: %ld Blocks = %ld kBytes = %ld MBytes = %ld prMB\n",
+ (long)usalp->cap->c_baddr+1, kb, mb, prmb);
+ fprintf(f, "Sectorsize: %ld Bytes\n", (long)usalp->cap->c_bsize);
+}
+
+int
+scsi_load_unload(SCSI *usalp, int load)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xA6;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g5_cdb.addr[1] = load?3:2;
+ scmd->cdb.g5_cdb.count[2] = 0; /* slot # */
+
+ usalp->cmdname = "medium load/unload";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+scsi_prevent_removal(SCSI *usalp, int prevent)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = 0x1E;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.count = prevent & 1;
+
+ usalp->cmdname = "prevent/allow medium removal";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+
+int
+scsi_start_stop_unit(SCSI *usalp, int flg, int loej, BOOL immed)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = 0x1B; /* Start Stop Unit */
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.count = (flg ? 1:0) | (loej ? 2:0);
+
+ if (immed)
+ scmd->cdb.cmd_cdb[1] |= 0x01;
+
+ usalp->cmdname = "start/stop unit";
+
+ return (usal_cmd(usalp));
+}
+
+int
+scsi_set_streaming(SCSI *usalp, caddr_t perf_desc, int size)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = perf_desc;
+ scmd->size = size;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xB6;
+ scmd->cdb.cmd_cdb[11] = 0;
+ scmd->cdb.cmd_cdb[10] = size;
+
+ usalp->cmdname = "set streaming";
+
+ if(usalp->verbose)
+ fprintf(stderr, "scsi_set_streaming\n");
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+scsi_set_speed(SCSI *usalp, int readspeed, int writespeed, int rotctl)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xBB;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+
+ if (readspeed < 0)
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], 0xFFFF);
+ else
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], readspeed);
+ if (writespeed < 0)
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xFFFF);
+ else
+ i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], writespeed);
+
+ scmd->cdb.cmd_cdb[1] |= rotctl & 0x03;
+
+ usalp->cmdname = "set cd speed";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+scsi_get_speed(SCSI *usalp, int *readspeedp, int *writespeedp)
+{
+ struct cd_mode_page_2A *mp;
+ Uchar m[256];
+ int val;
+
+ usalp->silent++;
+ mp = mmc_cap(usalp, m); /* Get MMC capabilities in allocated mp */
+ usalp->silent--;
+ if (mp == NULL)
+ return (-1); /* Pre SCSI-3/mmc drive */
+
+ val = a_to_u_2_byte(mp->cur_read_speed);
+ if (readspeedp)
+ *readspeedp = val;
+
+ if (mp->p_len >= 28)
+ val = a_to_u_2_byte(mp->v3_cur_write_speed);
+ else
+ val = a_to_u_2_byte(mp->cur_write_speed);
+ if (writespeedp)
+ *writespeedp = val;
+
+ return (0);
+}
+
+
+int
+qic02(SCSI *usalp, int cmd)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)0;
+ scmd->size = 0;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = DEF_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = 0x0D; /* qic02 Sysgen SC4000 */
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.mid_addr = cmd;
+
+ usalp->cmdname = "qic 02";
+ return (usal_cmd(usalp));
+}
+
+#define G0_MAXADDR 0x1FFFFFL
+
+int
+write_xscsi(SCSI *usalp, caddr_t bp, long addr, long size, int cnt)
+{
+ if (addr <= G0_MAXADDR)
+ return (write_xg0(usalp, bp, addr, size, cnt));
+ else
+ return (write_xg1(usalp, bp, addr, size, cnt));
+}
+
+int
+write_xg0(SCSI *usalp,
+ caddr_t bp /* address of buffer */,
+ long addr /* disk address (sector) to put */,
+ long size /* number of bytes to transfer */,
+ int cnt /* sectorcount */)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = size;
+ scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
+/* scmd->flags = SCG_DISRE_ENA;*/
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_WRITE;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
+ scmd->cdb.g0_cdb.count = cnt;
+
+ usalp->cmdname = "write_g0";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (size - usal_getresid(usalp));
+}
+
+int
+write_xg1(SCSI *usalp,
+ caddr_t bp /* address of buffer */,
+ long addr /* disk address (sector) to put */,
+ long size /* number of bytes to transfer */,
+ int cnt /* sectorcount */)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = size;
+ scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
+/* scmd->flags = SCG_DISRE_ENA;*/
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = SC_EWRITE;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "write_g1";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (size - usal_getresid(usalp));
+}
+
+int
+write_xg5(SCSI *usalp,
+ caddr_t bp /* address of buffer */,
+ long addr /* disk address (sector) to put */,
+ long size /* number of bytes to transfer */,
+ int cnt /* sectorcount */)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = size;
+ scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
+/* scmd->flags = SCG_DISRE_ENA;*/
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g5_cdb.cmd = 0xAA;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+ g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
+ g5_cdblen(&scmd->cdb.g5_cdb, cnt);
+
+ usalp->cmdname = "write_g5";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (size - usal_getresid(usalp));
+}
+
+int
+seek_scsi(SCSI *usalp, long addr)
+{
+ if (addr <= G0_MAXADDR)
+ return (seek_g0(usalp, addr));
+ else
+ return (seek_g1(usalp, addr));
+}
+
+int
+seek_g0(SCSI *usalp, long addr)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = 0x0B; /* Seek */
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
+
+ usalp->cmdname = "seek_g0";
+
+ return (usal_cmd(usalp));
+}
+
+int
+seek_g1(SCSI *usalp, long addr)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x2B; /* Seek G1 */
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
+
+ usalp->cmdname = "seek_g1";
+
+ return (usal_cmd(usalp));
+}
+
+int
+scsi_flush_cache(SCSI *usalp, BOOL immed)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 2 * 60; /* Max: sizeof (CDR-cache)/150KB/s */
+ scmd->cdb.g1_cdb.cmd = 0x35;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+
+ if (immed)
+ scmd->cdb.cmd_cdb[1] |= 0x02;
+
+ usalp->cmdname = "flush cache";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_buffer(SCSI *usalp, caddr_t bp, int cnt, int mode)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->dma_read = 1;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x3C; /* Read Buffer */
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.cmd_cdb[1] |= (mode & 7);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read buffer";
+
+ return (usal_cmd(usalp));
+}
+
+int
+write_buffer(SCSI *usalp, char *buffer, long length, int mode, int bufferid,
+ long offset)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ char *cdb;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = buffer;
+ scmd->size = length;
+ scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+
+ cdb = (char *)scmd->cdb.cmd_cdb;
+
+ cdb[0] = 0x3B;
+ cdb[1] = mode & 7;
+ cdb[2] = bufferid;
+ cdb[3] = offset >> 16;
+ cdb[4] = (offset >> 8) & 0xff;
+ cdb[5] = offset & 0xff;
+ cdb[6] = length >> 16;
+ cdb[7] = (length >> 8) & 0xff;
+ cdb[8] = length & 0xff;
+
+ usalp->cmdname = "write_buffer";
+
+ if (usal_cmd(usalp) >= 0)
+ return (1);
+ return (0);
+}
+
+int
+read_subchannel(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int subq,
+ int fmt)
+
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x42;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ if (msf)
+ scmd->cdb.g1_cdb.res = 1;
+ if (subq)
+ scmd->cdb.g1_cdb.addr[0] = 0x40;
+ scmd->cdb.g1_cdb.addr[1] = fmt;
+ scmd->cdb.g1_cdb.res6 = track;
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read subchannel";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_toc(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int fmt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x43;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ if (msf)
+ scmd->cdb.g1_cdb.res = 1;
+ scmd->cdb.g1_cdb.addr[0] = fmt & 0x0F;
+ scmd->cdb.g1_cdb.res6 = track;
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read toc";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_toc_philips(SCSI *usalp, caddr_t bp, int track, int cnt, int msf, int fmt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 4 * 60; /* May last 174s on a TEAC CD-R55S */
+ scmd->cdb.g1_cdb.cmd = 0x43;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ if (msf)
+ scmd->cdb.g1_cdb.res = 1;
+ scmd->cdb.g1_cdb.res6 = track;
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ if (fmt & 1)
+ scmd->cdb.g1_cdb.vu_96 = 1;
+ if (fmt & 2)
+ scmd->cdb.g1_cdb.vu_97 = 1;
+
+ usalp->cmdname = "read toc";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_header(SCSI *usalp, caddr_t bp, long addr, int cnt, int msf)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x44;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ if (msf)
+ scmd->cdb.g1_cdb.res = 1;
+ g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read header";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_disk_info(SCSI *usalp, caddr_t bp, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 4 * 60; /* Needs up to 2 minutes */
+ scmd->cdb.g1_cdb.cmd = 0x51;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read disk info";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_track_info(SCSI *usalp, caddr_t bp, int type, int addr, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 4 * 60; /* Needs up to 2 minutes */
+ scmd->cdb.g1_cdb.cmd = 0x52;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+/* scmd->cdb.cmd_cdb[1] = type & 0x03;*/
+ scmd->cdb.cmd_cdb[1] = type;
+ g1_cdbaddr(&scmd->cdb.g1_cdb, addr); /* LBA/Track/Session */
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read track info";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+reserve_track(SCSI *usalp, Ulong size)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x53;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ i_to_4_byte(&scmd->cdb.g1_cdb.addr[3], size);
+
+ usalp->cmdname = "reserve track";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+
+ return (0);
+
+}
+
+int
+read_rzone_info(SCSI *usalp, caddr_t bp, int cnt)
+{
+ return (read_track_info(usalp, bp, TI_TYPE_LBA, 0, cnt));
+}
+
+int
+reserve_tr_rzone(SCSI *usalp, long size /* number of blocks */)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)0;
+ scmd->size = 0;
+ scmd->flags = SCG_DISRE_ENA|SCG_CMD_RETRY;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x53;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+
+ i_to_4_byte(&scmd->cdb.g1_cdb.addr[3], size);
+
+ usalp->cmdname = "reserve_track_rzone";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int addr, int layer,
+ int fmt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 4 * 60; /* Needs up to 2 minutes ??? */
+ scmd->cdb.g5_cdb.cmd = 0xAD;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+ g5_cdbaddr(&scmd->cdb.g5_cdb, addr);
+ g5_cdblen(&scmd->cdb.g5_cdb, cnt);
+ scmd->cdb.g5_cdb.count[0] = layer;
+ scmd->cdb.g5_cdb.count[1] = fmt;
+
+ usalp->cmdname = "read dvd structure";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+send_dvd_structure(SCSI *usalp, caddr_t bp, int cnt, int layer, int fmt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 4 * 60; /* Needs up to 2 minutes ??? */
+ scmd->cdb.g5_cdb.cmd = 0xBF;
+ scmd->cdb.g5_cdb.lun = usal_lun(usalp);
+ g5_cdblen(&scmd->cdb.g5_cdb, cnt);
+
+ scmd->cdb.cmd_cdb[7] = fmt;
+
+ usalp->cmdname = "send dvd structure";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+send_opc(SCSI *usalp, caddr_t bp, int cnt, int doopc)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 60;
+ scmd->cdb.g1_cdb.cmd = 0x54;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g1_cdb.reladr = doopc?1:0;
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "send opc";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_track_info_philips(SCSI *usalp, caddr_t bp, int track, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0xE5;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdbaddr(&scmd->cdb.g1_cdb, track);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read track info";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+scsi_close_tr_session(SCSI *usalp, int type, int track, BOOL immed)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 8 * 60; /* Needs up to 4 minutes */
+ scmd->cdb.g1_cdb.cmd = 0x5B;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g1_cdb.addr[0] = type;
+ scmd->cdb.g1_cdb.addr[3] = track;
+
+ if (immed)
+ scmd->cdb.g1_cdb.reladr = 1;
+/* scmd->cdb.cmd_cdb[1] |= 0x01;*/
+#ifdef nono
+ scmd->cdb.g1_cdb.reladr = 1; /* IMM hack to test Mitsumi behaviour*/
+#endif
+
+ usalp->cmdname = "close track/session";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+read_master_cue(SCSI *usalp, caddr_t bp, int sheet, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x59; /* Read master cue */
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g1_cdb.addr[2] = sheet;
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read master cue";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (0);
+}
+
+int
+send_cue_sheet(SCSI *usalp, caddr_t bp, long size)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = size;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x5D; /* Send CUE sheet */
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdblen(&scmd->cdb.g1_cdb, size);
+
+ usalp->cmdname = "send_cue_sheet";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ return (size - scmd->resid);
+}
+
+int
+read_buff_cap(SCSI *usalp, long *sp, long *fp)
+{
+ char resp[12];
+ Ulong freespace;
+ Ulong bufsize;
+ int per;
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)resp;
+ scmd->size = sizeof (resp);
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x5C; /* Read buffer cap */
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdblen(&scmd->cdb.g1_cdb, sizeof (resp));
+
+ usalp->cmdname = "read buffer cap";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+
+ bufsize = a_to_u_4_byte(&resp[4]);
+ freespace = a_to_u_4_byte(&resp[8]);
+ if (sp)
+ *sp = bufsize;
+ if (fp)
+ *fp = freespace;
+
+ if (usalp->verbose || (sp == 0 && fp == 0))
+ printf("BFree: %ld K BSize: %ld K\n", freespace >> 10, bufsize >> 10);
+
+ if (bufsize == 0)
+ return (0);
+ per = (100 * (bufsize - freespace)) / bufsize;
+ if (per < 0)
+ return (0);
+ if (per > 100)
+ return (100);
+ return (per);
+}
+
+int
+scsi_blank(SCSI *usalp, long addr, int blanktype, BOOL immed)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 160 * 60; /* full blank at 1x could take 80 minutes */
+ scmd->cdb.g5_cdb.cmd = 0xA1; /* Blank */
+ scmd->cdb.g0_cdb.high_addr = blanktype;
+ g1_cdbaddr(&scmd->cdb.g5_cdb, addr);
+
+ if (immed)
+ scmd->cdb.g5_cdb.res |= 8;
+/* scmd->cdb.cmd_cdb[1] |= 0x10;*/
+
+ usalp->cmdname = "blank unit";
+
+ return (usal_cmd(usalp));
+}
+
+int
+scsi_format(SCSI *usalp, caddr_t addr, int size, BOOL background)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+ int progress=0, ret=-1, pid=-1;
+ unsigned char sense_table[18];
+ int i;
+
+ printf("scsi_format: preparing\n");
+
+ fillbytes((caddr_t)scmd, sizeof(*scmd), '\0');
+ scmd->addr = addr;
+ scmd->size = size;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G5_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->timeout = 160 * 60; /* Do not know what to set */
+ scmd->cdb.g5_cdb.cmd = 0x04; /* Format Unit */
+ scmd->cdb.cmd_cdb[1] = 0x11; /* "FmtData" and "Format Code" */
+ scmd->cdb.cmd_cdb[5] = 0;
+
+ usalp->cmdname = "format unit";
+
+ printf("scsi_format: running\n");
+ ret = (usal_cmd(usalp));
+ printf("scsi_format: post processing %d\n", ret);
+ if (ret == -1) return ret;
+ if (background) {
+ if ((pid=fork()) == (pid_t)-1)
+ perror ("- [unable to fork()]");
+ else {
+ if (!pid) {
+ while (1) {
+ if (test_unit_ready(usalp) >= 0)
+ break;
+ sleep(1);
+ }
+ return ret;
+ }
+ }
+ }
+ printf("Formating in progress: 0.00 %% done.");
+ sleep(20);
+ i = 0;
+ while (progress < 0xfff0 && !(progress == 0 && i > 50)) {
+ test_unit_ready(usalp);
+ request_sense_b(usalp, (caddr_t)sense_table, 18);
+ progress = sense_table[16]<<8|sense_table[17];
+ printf("\rFormating in progress: %.2f %% done [%d]. ", (float)(progress*100)/0x10000,progress);
+ usleep(100000);
+ i++;
+ /*for (i=0; i < 18; i++) {
+ printf("%d ", sense_table[i]);
+ }*/
+ }
+ sleep(10);
+ printf("\rFormating in progress: 100.00 %% done. \n");
+ if (pid) exit (0);
+ return ret;
+}
+
+/*
+ * XXX First try to handle ATAPI:
+ * XXX ATAPI cannot handle SCSI 6 byte commands.
+ * XXX We try to simulate 6 byte mode sense/select.
+ */
+static BOOL is_atapi;
+
+BOOL
+allow_atapi(SCSI *usalp, BOOL new)
+{
+ BOOL old = is_atapi;
+ Uchar mode[256];
+
+ if (new == old)
+ return (old);
+
+ usalp->silent++;
+ /*
+ * If a bad drive has been reset before, we may need to fire up two
+ * test unit ready commands to clear status.
+ */
+ (void) unit_ready(usalp);
+ if (new &&
+ mode_sense_g1(usalp, mode, 8, 0x3F, 0) < 0) { /* All pages current */
+ new = FALSE;
+ }
+ usalp->silent--;
+
+ is_atapi = new;
+ return (old);
+}
+
+int
+mode_select(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
+{
+ if (is_atapi)
+ return (mode_select_sg0(usalp, dp, cnt, smp, pf));
+ return (mode_select_g0(usalp, dp, cnt, smp, pf));
+}
+
+int
+mode_sense(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
+{
+ if (is_atapi)
+ return (mode_sense_sg0(usalp, dp, cnt, page, pcf));
+ return (mode_sense_g0(usalp, dp, cnt, page, pcf));
+}
+
+/*
+ * Simulate mode select g0 with mode select g1.
+ */
+int
+mode_select_sg0(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
+{
+ Uchar xmode[256+4];
+ int amt = cnt;
+
+ if (amt < 1 || amt > 255) {
+ /* XXX clear SCSI error codes ??? */
+ return (-1);
+ }
+
+ if (amt < 4) { /* Data length. medium type & VU */
+ amt += 1;
+ } else {
+ amt += 4;
+ movebytes(&dp[4], &xmode[8], cnt-4);
+ }
+ xmode[0] = 0;
+ xmode[1] = 0;
+ xmode[2] = dp[1];
+ xmode[3] = dp[2];
+ xmode[4] = 0;
+ xmode[5] = 0;
+ i_to_2_byte(&xmode[6], (unsigned int)dp[3]);
+
+ if (usalp->verbose) usal_prbytes("Mode Parameters (un-converted)", dp, cnt);
+
+ return (mode_select_g1(usalp, xmode, amt, smp, pf));
+}
+
+/*
+ * Simulate mode sense g0 with mode sense g1.
+ */
+int
+mode_sense_sg0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
+{
+ Uchar xmode[256+4];
+ int amt = cnt;
+ int len;
+
+ if (amt < 1 || amt > 255) {
+ /* XXX clear SCSI error codes ??? */
+ return (-1);
+ }
+
+ fillbytes((caddr_t)xmode, sizeof (xmode), '\0');
+ if (amt < 4) { /* Data length. medium type & VU */
+ amt += 1;
+ } else {
+ amt += 4;
+ }
+ if (mode_sense_g1(usalp, xmode, amt, page, pcf) < 0)
+ return (-1);
+
+ amt = cnt - usal_getresid(usalp);
+/*
+ * For tests: Solaris 8 & LG CD-ROM always returns resid == amt
+ */
+/* amt = cnt;*/
+ if (amt > 4)
+ movebytes(&xmode[8], &dp[4], amt-4);
+ len = a_to_u_2_byte(xmode);
+ if (len == 0) {
+ dp[0] = 0;
+ } else if (len < 6) {
+ if (len > 2)
+ len = 2;
+ dp[0] = len;
+ } else {
+ dp[0] = len - 3;
+ }
+ dp[1] = xmode[2];
+ dp[2] = xmode[3];
+ len = a_to_u_2_byte(&xmode[6]);
+ dp[3] = len;
+
+ if (usalp->verbose) usal_prbytes("Mode Sense Data (converted)", dp, amt);
+ return (0);
+}
+
+int
+mode_select_g0(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)dp;
+ scmd->size = cnt;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_MODE_SELECT;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.high_addr = smp ? 1 : 0 | pf ? 0x10 : 0;
+ scmd->cdb.g0_cdb.count = cnt;
+
+ if (usalp->verbose) {
+ fprintf(stderr, "%s ", smp?"Save":"Set ");
+ usal_prbytes("Mode Parameters", dp, cnt);
+ }
+
+ usalp->cmdname = "mode select g0";
+
+ return (usal_cmd(usalp));
+}
+
+int
+mode_select_g1(SCSI *usalp, Uchar *dp, int cnt, int smp, int pf)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)dp;
+ scmd->size = cnt;
+ scmd->flags = SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x55;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ scmd->cdb.g0_cdb.high_addr = smp ? 1 : 0 | pf ? 0x10 : 0;
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ if (usalp->verbose) {
+ printf("%s ", smp?"Save":"Set ");
+ usal_prbytes("Mode Parameters", dp, cnt);
+ }
+
+ usalp->cmdname = "mode select g1";
+
+ return (usal_cmd(usalp));
+}
+
+int
+mode_sense_g0(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)dp;
+ scmd->size = 0xFF;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_MODE_SENSE;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+#ifdef nonono
+ scmd->cdb.g0_cdb.high_addr = 1<<4; /* DBD Disable Block desc. */
+#endif
+ scmd->cdb.g0_cdb.mid_addr = (page&0x3F) | ((pcf<<6)&0xC0);
+ scmd->cdb.g0_cdb.count = page ? 0xFF : 24;
+ scmd->cdb.g0_cdb.count = cnt;
+
+ usalp->cmdname = "mode sense g0";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ if (usalp->verbose) usal_prbytes("Mode Sense Data", dp, cnt - usal_getresid(usalp));
+ return (0);
+}
+
+int
+mode_sense_g1(SCSI *usalp, Uchar *dp, int cnt, int page, int pcf)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = (caddr_t)dp;
+ scmd->size = cnt;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = 0x5A;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+#ifdef nonono
+ scmd->cdb.g0_cdb.high_addr = 1<<4; /* DBD Disable Block desc. */
+#endif
+ scmd->cdb.g1_cdb.addr[0] = (page&0x3F) | ((pcf<<6)&0xC0);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "mode sense g1";
+
+ if (usal_cmd(usalp) < 0)
+ return (-1);
+ if (usalp->verbose) usal_prbytes("Mode Sense Data", dp, cnt - usal_getresid(usalp));
+ return (0);
+}
+
+struct trackdesc {
+ Uchar res0;
+
+#if defined(_BIT_FIELDS_LTOH) /* Intel byteorder */
+ Ucbit control : 4;
+ Ucbit adr : 4;
+#else /* Motorola byteorder */
+ Ucbit adr : 4;
+ Ucbit control : 4;
+#endif
+
+ Uchar track;
+ Uchar res3;
+ Uchar addr[4];
+};
+
+struct diskinfo {
+ struct tocheader hd;
+ struct trackdesc desc[1];
+};
+
+struct siheader {
+ Uchar len[2];
+ Uchar finished;
+ Uchar unfinished;
+};
+
+struct sidesc {
+ Uchar sess_number;
+ Uchar res1;
+ Uchar track;
+ Uchar res3;
+ Uchar addr[4];
+};
+
+struct sinfo {
+ struct siheader hd;
+ struct sidesc desc[1];
+};
+
+struct trackheader {
+ Uchar mode;
+ Uchar res[3];
+ Uchar addr[4];
+};
+#define TRM_ZERO 0
+#define TRM_USER_ECC 1 /* 2048 bytes user data + 288 Bytes ECC/EDC */
+#define TRM_USER 2 /* All user data (2336 bytes) */
+
+
+int
+read_tochdr(SCSI *usalp, cdr_t *dp, int *fp, int *lp)
+{
+ struct tocheader *tp;
+ char xb[256];
+ int len;
+
+ tp = (struct tocheader *)xb;
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+ if (read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_TOC) < 0) {
+ if (usalp->silent == 0)
+ errmsgno(EX_BAD, "Cannot read TOC header\n");
+ return (-1);
+ }
+ len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
+ if (len >= 4) {
+ if (fp)
+ *fp = tp->first;
+ if (lp)
+ *lp = tp->last;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+read_cdtext(SCSI *usalp)
+{
+ struct tocheader *tp;
+ char xb[256];
+ int len;
+ char xxb[10000];
+
+ tp = (struct tocheader *)xb;
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+ if (read_toc(usalp, xb, 0, sizeof (struct tocheader), 0, FMT_CDTEXT) < 0) {
+ if (usalp->silent == 0 || usalp->verbose > 0)
+ errmsgno(EX_BAD, "Cannot read CD-Text header\n");
+ return (-1);
+ }
+ len = a_to_u_2_byte(tp->len) + sizeof (struct tocheader)-2;
+ printf("CD-Text len: %d\n", len);
+
+ if (read_toc(usalp, xxb, 0, len, 0, FMT_CDTEXT) < 0) {
+ if (usalp->silent == 0)
+ errmsgno(EX_BAD, "Cannot read CD-Text\n");
+ return (-1);
+ }
+ {
+ FILE *f = fileopen("cdtext.dat", "wctb");
+ filewrite(f, xxb, len);
+ }
+ return (0);
+}
+
+int
+read_trackinfo(SCSI *usalp, int track, long *offp, struct msf *msfp, int *adrp,
+ int *controlp, int *modep)
+{
+ struct diskinfo *dp;
+ char xb[256];
+ int len;
+
+ dp = (struct diskinfo *)xb;
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+ if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 0, FMT_TOC) < 0) {
+ if (usalp->silent <= 0)
+ errmsgno(EX_BAD, "Cannot read TOC\n");
+ return (-1);
+ }
+ len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
+ if (len < (int)sizeof (struct diskinfo))
+ return (-1);
+
+ if (offp)
+ *offp = a_to_4_byte(dp->desc[0].addr);
+ if (adrp)
+ *adrp = dp->desc[0].adr;
+ if (controlp)
+ *controlp = dp->desc[0].control;
+
+ if (msfp) {
+ usalp->silent++;
+ if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 1, FMT_TOC)
+ >= 0) {
+ msfp->msf_min = dp->desc[0].addr[1];
+ msfp->msf_sec = dp->desc[0].addr[2];
+ msfp->msf_frame = dp->desc[0].addr[3];
+ } else if (read_toc(usalp, xb, track, sizeof (struct diskinfo), 0, FMT_TOC)
+ >= 0) {
+ /*
+ * Some drives (e.g. the Philips CDD-522) don't support
+ * to read the TOC in MSF mode.
+ */
+ long off = a_to_4_byte(dp->desc[0].addr);
+
+ lba_to_msf(off, msfp);
+ } else {
+ msfp->msf_min = 0;
+ msfp->msf_sec = 0;
+ msfp->msf_frame = 0;
+ }
+ usalp->silent--;
+ }
+
+ if (modep == NULL)
+ return (0);
+
+ if (track == 0xAA) {
+ *modep = -1;
+ return (0);
+ }
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+
+ usalp->silent++;
+ if (read_header(usalp, xb, *offp, 8, 0) >= 0) {
+ *modep = xb[0];
+ } else if (read_track_info_philips(usalp, xb, track, 14) >= 0) {
+ *modep = xb[0xb] & 0xF;
+ } else {
+ *modep = -1;
+ }
+ usalp->silent--;
+ return (0);
+}
+
+int
+read_B0(SCSI *usalp, BOOL isbcd, long *b0p, long *lop)
+{
+ struct fdiskinfo *dp;
+ struct ftrackdesc *tp;
+ char xb[8192];
+ char *pe;
+ int len;
+ long l;
+
+ dp = (struct fdiskinfo *)xb;
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+ if (read_toc_philips(usalp, xb, 1, sizeof (struct tocheader), 0, FMT_FULLTOC) < 0) {
+ return (-1);
+ }
+ len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
+ if (len < (int)sizeof (struct fdiskinfo))
+ return (-1);
+ if (read_toc_philips(usalp, xb, 1, len, 0, FMT_FULLTOC) < 0) {
+ return (-1);
+ }
+ if (usalp->verbose) {
+ usal_prbytes("TOC data: ", (Uchar *)xb,
+ len > (int)sizeof (xb) - usal_getresid(usalp) ?
+ sizeof (xb) - usal_getresid(usalp) : len);
+
+ tp = &dp->desc[0];
+ pe = &xb[len];
+
+ while ((char *)tp < pe) {
+ usal_prbytes("ENT: ", (Uchar *)tp, 11);
+ tp++;
+ }
+ }
+ tp = &dp->desc[0];
+ pe = &xb[len];
+
+ for (; (char *)tp < pe; tp++) {
+ if (tp->sess_number != dp->hd.last)
+ continue;
+ if (tp->point != 0xB0)
+ continue;
+ if (usalp->verbose)
+ usal_prbytes("B0: ", (Uchar *)tp, 11);
+ if (isbcd) {
+ l = msf_to_lba(from_bcd(tp->amin),
+ from_bcd(tp->asec),
+ from_bcd(tp->aframe), TRUE);
+ } else {
+ l = msf_to_lba(tp->amin,
+ tp->asec,
+ tp->aframe, TRUE);
+ }
+ if (b0p)
+ *b0p = l;
+
+ if (usalp->verbose)
+ printf("B0 start: %ld\n", l);
+
+ if (isbcd) {
+ l = msf_to_lba(from_bcd(tp->pmin),
+ from_bcd(tp->psec),
+ from_bcd(tp->pframe), TRUE);
+ } else {
+ l = msf_to_lba(tp->pmin,
+ tp->psec,
+ tp->pframe, TRUE);
+ }
+
+ if (usalp->verbose)
+ printf("B0 lout: %ld\n", l);
+ if (lop)
+ *lop = l;
+ return (0);
+ }
+ return (-1);
+}
+
+
+/*
+ * Return address of first track in last session (SCSI-3/mmc version).
+ */
+int
+read_session_offset(SCSI *usalp, long *offp)
+{
+ struct diskinfo *dp;
+ char xb[256];
+ int len;
+
+ dp = (struct diskinfo *)xb;
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+ if (read_toc(usalp, (caddr_t)xb, 0, sizeof (struct tocheader), 0, FMT_SINFO) < 0)
+ return (-1);
+
+ if (usalp->verbose)
+ usal_prbytes("tocheader: ",
+ (Uchar *)xb, sizeof (struct tocheader) - usal_getresid(usalp));
+
+ len = a_to_u_2_byte(dp->hd.len) + sizeof (struct tocheader)-2;
+ if (len > (int)sizeof (xb)) {
+ errmsgno(EX_BAD, "Session info too big.\n");
+ return (-1);
+ }
+ if (read_toc(usalp, (caddr_t)xb, 0, len, 0, FMT_SINFO) < 0)
+ return (-1);
+
+ if (usalp->verbose)
+ usal_prbytes("tocheader: ",
+ (Uchar *)xb, len - usal_getresid(usalp));
+
+ dp = (struct diskinfo *)xb;
+ if (offp)
+ *offp = a_to_u_4_byte(dp->desc[0].addr);
+ return (0);
+}
+
+/*
+ * Return address of first track in last session (pre SCSI-3 version).
+ */
+int
+read_session_offset_philips(SCSI *usalp, long *offp)
+{
+ struct sinfo *sp;
+ char xb[256];
+ int len;
+
+ sp = (struct sinfo *)xb;
+
+ fillbytes((caddr_t)xb, sizeof (xb), '\0');
+ if (read_toc_philips(usalp, (caddr_t)xb, 0, sizeof (struct siheader), 0, FMT_SINFO) < 0)
+ return (-1);
+ len = a_to_u_2_byte(sp->hd.len) + sizeof (struct siheader)-2;
+ if (len > (int)sizeof (xb)) {
+ errmsgno(EX_BAD, "Session info too big.\n");
+ return (-1);
+ }
+ if (read_toc_philips(usalp, (caddr_t)xb, 0, len, 0, FMT_SINFO) < 0)
+ return (-1);
+ /*
+ * Old drives return the number of finished sessions in first/finished
+ * a descriptor is returned for each session.
+ * New drives return the number of the first and last session
+ * one descriptor for the last finished session is returned
+ * as in SCSI-3
+ * In all cases the lowest session number is set to 1.
+ */
+ sp = (struct sinfo *)xb;
+ if (offp)
+ *offp = a_to_u_4_byte(sp->desc[sp->hd.finished-1].addr);
+ return (0);
+}
+
+int
+sense_secsize(SCSI *usalp, int current)
+{
+ Uchar mode[0x100];
+ Uchar *p;
+ Uchar *ep;
+ int len;
+ int secsize = -1;
+
+ usalp->silent++;
+ (void) unit_ready(usalp);
+ usalp->silent--;
+
+ /* XXX Quick and dirty, musz verallgemeinert werden !!! */
+
+ fillbytes(mode, sizeof (mode), '\0');
+ usalp->silent++;
+
+ len = sizeof (struct scsi_mode_header) +
+ sizeof (struct scsi_mode_blockdesc);
+ /*
+ * Wenn wir hier get_mode_params() nehmen bekommen wir die Warnung:
+ * Warning: controller returns wrong page 1 for All pages page (3F).
+ */
+ if (mode_sense(usalp, mode, len, 0x3F, current?0:2) < 0) {
+ fillbytes(mode, sizeof (mode), '\0');
+ if (mode_sense(usalp, mode, len, 0, current?0:2) < 0) { /* VU (block desc) */
+ usalp->silent--;
+ return (-1);
+ }
+ }
+ if (mode[3] == 8) {
+ if (usalp->debug) {
+ printf("Density: 0x%X\n", mode[4]);
+ printf("Blocks: %ld\n", a_to_u_3_byte(&mode[5]));
+ printf("Blocklen:%ld\n", a_to_u_3_byte(&mode[9]));
+ }
+ secsize = a_to_u_3_byte(&mode[9]);
+ }
+ fillbytes(mode, sizeof (mode), '\0');
+ /*
+ * The ACARD TECH AEC-7720 ATAPI<->SCSI adaptor
+ * chokes if we try to transfer more than 0x40 bytes with
+ * mode_sense of all pages. So try to avoid to run this
+ * command if possible.
+ */
+ if (usalp->debug &&
+ mode_sense(usalp, mode, 0xFE, 0x3F, current?0:2) >= 0) { /* All Pages */
+
+ ep = mode+mode[0]; /* Points to last byte of data */
+ p = &mode[4];
+ p += mode[3];
+ printf("Pages: ");
+ while (p < ep) {
+ printf("0x%X ", *p&0x3F);
+ p += p[1]+2;
+ }
+ printf("\n");
+ }
+ usalp->silent--;
+
+ return (secsize);
+}
+
+int
+select_secsize(SCSI *usalp, int secsize)
+{
+ struct scsi_mode_data md;
+ int count = sizeof (struct scsi_mode_header) +
+ sizeof (struct scsi_mode_blockdesc);
+
+ (void) test_unit_ready(usalp); /* clear any error situation */
+
+ fillbytes((caddr_t)&md, sizeof (md), '\0');
+ md.header.blockdesc_len = 8;
+ i_to_3_byte(md.blockdesc.lblen, secsize);
+
+ return (mode_select(usalp, (Uchar *)&md, count, 0, usalp->inq->data_format >= 2));
+}
+
+BOOL
+is_cddrive(SCSI *usalp)
+{
+ return (usalp->inq->type == INQ_ROMD || usalp->inq->type == INQ_WORM);
+}
+
+BOOL
+is_unknown_dev(SCSI *usalp)
+{
+ return (usalp->dev == DEV_UNKNOWN);
+}
+
+#ifndef DEBUG
+#define DEBUG
+#endif
+#ifdef DEBUG
+
+int
+read_scsi(SCSI *usalp, caddr_t bp, long addr, int cnt)
+{
+ if (addr <= G0_MAXADDR && cnt < 256 && !is_atapi)
+ return (read_g0(usalp, bp, addr, cnt));
+ else
+ return (read_g1(usalp, bp, addr, cnt));
+}
+
+int
+read_g0(SCSI *usalp, caddr_t bp, long addr, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ if (usalp->cap->c_bsize <= 0)
+ raisecond("capacity_not_set", 0L);
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt*usalp->cap->c_bsize;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G0_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g0_cdb.cmd = SC_READ;
+ scmd->cdb.g0_cdb.lun = usal_lun(usalp);
+ g0_cdbaddr(&scmd->cdb.g0_cdb, addr);
+ scmd->cdb.g0_cdb.count = cnt;
+/* scmd->cdb.g0_cdb.vu_56 = 1;*/
+
+ usalp->cmdname = "read_g0";
+
+ return (usal_cmd(usalp));
+}
+
+int
+read_g1(SCSI *usalp, caddr_t bp, long addr, int cnt)
+{
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ if (usalp->cap->c_bsize <= 0)
+ raisecond("capacity_not_set", 0L);
+
+ fillbytes((caddr_t)scmd, sizeof (*scmd), '\0');
+ scmd->addr = bp;
+ scmd->size = cnt*usalp->cap->c_bsize;
+ scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA;
+ scmd->cdb_len = SC_G1_CDBLEN;
+ scmd->sense_len = CCS_SENSE_LEN;
+ scmd->cdb.g1_cdb.cmd = SC_EREAD;
+ scmd->cdb.g1_cdb.lun = usal_lun(usalp);
+ g1_cdbaddr(&scmd->cdb.g1_cdb, addr);
+ g1_cdblen(&scmd->cdb.g1_cdb, cnt);
+
+ usalp->cmdname = "read_g1";
+
+ return (usal_cmd(usalp));
+}
+#endif /* DEBUG */
+
+BOOL
+getdev(SCSI *usalp, BOOL print)
+{
+ BOOL got_inquiry = TRUE;
+ char vendor_info[8+1];
+ char prod_ident[16+1];
+ char prod_revision[4+1];
+ int inq_len = 0;
+ register struct usal_cmd *scmd = usalp->scmd;
+ register struct scsi_inquiry *inq = usalp->inq;
+
+
+ fillbytes((caddr_t)inq, sizeof (*inq), '\0');
+ usalp->dev = DEV_UNKNOWN;
+ usalp->silent++;
+ (void) unit_ready(usalp);
+ if (scmd->error >= SCG_FATAL &&
+ !(scmd->scb.chk && scmd->sense_count > 0)) {
+ usalp->silent--;
+ return (FALSE);
+ }
+
+
+/* if (scmd->error < SCG_FATAL || scmd->scb.chk && scmd->sense_count > 0){*/
+
+ if (inquiry(usalp, (caddr_t)inq, sizeof (*inq)) < 0) {
+ got_inquiry = FALSE;
+ } else {
+ inq_len = sizeof (*inq) - usal_getresid(usalp);
+ }
+ if (!got_inquiry) {
+ if (usalp->verbose) {
+ printf(
+ "error: %d scb.chk: %d sense_count: %d sense.code: 0x%x\n",
+ scmd->error, scmd->scb.chk,
+ scmd->sense_count, scmd->sense.code);
+ }
+ /*
+ * Folgende Kontroller kennen das Kommando
+ * INQUIRY nicht:
+ *
+ * ADAPTEC ACB-4000, ACB-4010, ACB 4070
+ * SYSGEN SC4000
+ *
+ * Leider reagieren ACB40X0 und ACB5500 identisch
+ * wenn drive not ready (code == not ready),
+ * sie sind dann nicht zu unterscheiden.
+ */
+
+ if (scmd->scb.chk && scmd->sense_count == 4) {
+ /* Test auf SYSGEN */
+ (void) qic02(usalp, 0x12); /* soft lock on */
+ if (qic02(usalp, 1) < 0) { /* soft lock off */
+ usalp->dev = DEV_ACB40X0;
+/* usalp->dev = acbdev();*/
+ } else {
+ usalp->dev = DEV_SC4000;
+ inq->type = INQ_SEQD;
+ inq->removable = 1;
+ }
+ }
+ } else if (usalp->verbose) {
+ int i;
+ int len = inq->add_len + 5;
+ Uchar ibuf[256+5];
+ Uchar *ip = (Uchar *)inq;
+ Uchar c;
+
+ if (len > (int)sizeof (*inq) &&
+ inquiry(usalp, (caddr_t)ibuf, inq->add_len+5) >= 0) {
+ len = inq->add_len+5 - usal_getresid(usalp);
+ ip = ibuf;
+ } else {
+ len = sizeof (*inq);
+ }
+ printf("Inquiry Data : ");
+ for (i = 0; i < len; i++) {
+ c = ip[i];
+ if (c >= ' ' && c < 0177)
+ printf("%c", c);
+ else
+ printf(".");
+ }
+ printf("\n");
+ }
+
+ strncpy(vendor_info, inq->vendor_info, sizeof (inq->vendor_info));
+ strncpy(prod_ident, inq->prod_ident, sizeof (inq->prod_ident));
+ strncpy(prod_revision, inq->prod_revision, sizeof (inq->prod_revision));
+
+ vendor_info[sizeof (inq->vendor_info)] = '\0';
+ prod_ident[sizeof (inq->prod_ident)] = '\0';
+ prod_revision[sizeof (inq->prod_revision)] = '\0';
+
+ switch (inq->type) {
+
+ case INQ_DASD:
+ if (inq->add_len == 0 && inq->vendor_info[0] != '\0') {
+ Uchar *p;
+ /*
+ * NT-4.0 creates fake inquiry data for IDE disks.
+ * Unfortunately, it does not set add_len wo we
+ * check if vendor_info, prod_ident and prod_revision
+ * contains valid chars for a CCS inquiry.
+ */
+ if (inq_len >= 36)
+ inq->add_len = 31;
+
+ for (p = (Uchar *)&inq->vendor_info[0];
+ p < (Uchar *)&inq->prod_revision[4];
+ p++) {
+ if (*p < 0x20 || *p > 0x7E) {
+ inq->add_len = 0;
+ break;
+ }
+ }
+ }
+ if (inq->add_len == 0) {
+ if (usalp->dev == DEV_UNKNOWN && got_inquiry) {
+ usalp->dev = DEV_ACB5500;
+ strcpy(inq->vendor_info,
+ "ADAPTEC ACB-5500 FAKE");
+
+ } else switch (usalp->dev) {
+
+ case DEV_ACB40X0:
+ strcpy(inq->vendor_info,
+ "ADAPTEC ACB-40X0 FAKE");
+ break;
+ case DEV_ACB4000:
+ strcpy(inq->vendor_info,
+ "ADAPTEC ACB-4000 FAKE");
+ break;
+ case DEV_ACB4010:
+ strcpy(inq->vendor_info,
+ "ADAPTEC ACB-4010 FAKE");
+ break;
+ case DEV_ACB4070:
+ strcpy(inq->vendor_info,
+ "ADAPTEC ACB-4070 FAKE");
+ break;
+ }
+ } else if (inq->add_len < 31) {
+ usalp->dev = DEV_NON_CCS_DSK;
+
+ } else if (strbeg("EMULEX", vendor_info)) {
+ if (strbeg("MD21", prod_ident))
+ usalp->dev = DEV_MD21;
+ if (strbeg("MD23", prod_ident))
+ usalp->dev = DEV_MD23;
+ else
+ usalp->dev = DEV_CCS_GENDISK;
+ } else if (strbeg("ADAPTEC", vendor_info)) {
+ if (strbeg("ACB-4520", prod_ident))
+ usalp->dev = DEV_ACB4520A;
+ if (strbeg("ACB-4525", prod_ident))
+ usalp->dev = DEV_ACB4525;
+ else
+ usalp->dev = DEV_CCS_GENDISK;
+ } else if (strbeg("SONY", vendor_info) &&
+ strbeg("SMO-C501", prod_ident)) {
+ usalp->dev = DEV_SONY_SMO;
+ } else {
+ usalp->dev = DEV_CCS_GENDISK;
+ }
+ break;
+
+ case INQ_SEQD:
+ if (usalp->dev == DEV_SC4000) {
+ strcpy(inq->vendor_info,
+ "SYSGEN SC4000 FAKE");
+ } else if (inq->add_len == 0 &&
+ inq->removable &&
+ inq->ansi_version == 1) {
+ usalp->dev = DEV_MT02;
+ strcpy(inq->vendor_info,
+ "EMULEX MT02 FAKE");
+ }
+ break;
+
+/* case INQ_OPTD:*/
+ case INQ_ROMD:
+ case INQ_WORM:
+ if (strbeg("RXT-800S", prod_ident))
+ usalp->dev = DEV_RXT800S;
+
+ /*
+ * Start of CD-Recorders:
+ */
+ if (strbeg("ACER", vendor_info)) {
+ if (strbeg("CR-4020C", prod_ident))
+ usalp->dev = DEV_RICOH_RO_1420C;
+
+ } else if (strbeg("CREATIVE", vendor_info)) {
+ if (strbeg("CDR2000", prod_ident))
+ usalp->dev = DEV_RICOH_RO_1060C;
+
+ } else if (strbeg("GRUNDIG", vendor_info)) {
+ if (strbeg("CDR100IPW", prod_ident))
+ usalp->dev = DEV_CDD_2000;
+
+ } else if (strbeg("JVC", vendor_info)) {
+ if (strbeg("XR-W2001", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ else if (strbeg("XR-W2010", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ else if (strbeg("R2626", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+
+ } else if (strbeg("MITSBISH", vendor_info)) {
+
+#ifdef XXXX_REALLY
+ /* It's MMC compliant */
+ if (strbeg("CDRW226", prod_ident))
+ usalp->dev = DEV_MMC_CDRW;
+#else
+ /* EMPTY */
+#endif
+
+ } else if (strbeg("MITSUMI", vendor_info)) {
+ /* Don't know any product string */
+ usalp->dev = DEV_CDD_522;
+
+ } else if (strbeg("OPTIMA", vendor_info)) {
+ if (strbeg("CD-R 650", prod_ident))
+ usalp->dev = DEV_SONY_CDU_924;
+
+ } else if (strbeg("PHILIPS", vendor_info) ||
+ strbeg("IMS", vendor_info) ||
+ strbeg("KODAK", vendor_info) ||
+ strbeg("HP", vendor_info)) {
+
+ if (strbeg("CDD521/00", prod_ident))
+ usalp->dev = DEV_CDD_521_OLD;
+ else if (strbeg("CDD521/02", prod_ident))
+ usalp->dev = DEV_CDD_521_OLD; /* PCD 200R? */
+ else if (strbeg("CDD521", prod_ident))
+ usalp->dev = DEV_CDD_521;
+
+ if (strbeg("CDD522", prod_ident))
+ usalp->dev = DEV_CDD_522;
+ if (strbeg("PCD225", prod_ident))
+ usalp->dev = DEV_CDD_522;
+ if (strbeg("KHSW/OB", prod_ident)) /* PCD600 */
+ usalp->dev = DEV_PCD_600;
+ if (strbeg("CDR-240", prod_ident))
+ usalp->dev = DEV_CDD_2000;
+
+ if (strbeg("CDD20", prod_ident))
+ usalp->dev = DEV_CDD_2000;
+ if (strbeg("CDD26", prod_ident))
+ usalp->dev = DEV_CDD_2600;
+
+ if (strbeg("C4324/C4325", prod_ident))
+ usalp->dev = DEV_CDD_2000;
+ if (strbeg("CD-Writer 6020", prod_ident))
+ usalp->dev = DEV_CDD_2600;
+
+ } else if (strbeg("PINNACLE", vendor_info)) {
+ if (strbeg("RCD-1000", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ if (strbeg("RCD5020", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ if (strbeg("RCD5040", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ if (strbeg("RCD 4X4", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+
+ } else if (strbeg("PIONEER", vendor_info)) {
+ if (strbeg("CD-WO DW-S114X", prod_ident))
+ usalp->dev = DEV_PIONEER_DW_S114X;
+ else if (strbeg("CD-WO DR-R504X", prod_ident)) /* Reoprt from philip@merge.com */
+ usalp->dev = DEV_PIONEER_DW_S114X;
+ else if (strbeg("DVD-R DVR-S101", prod_ident))
+ usalp->dev = DEV_PIONEER_DVDR_S101;
+
+ } else if (strbeg("PLASMON", vendor_info)) {
+ if (strbeg("RF4100", prod_ident))
+ usalp->dev = DEV_PLASMON_RF_4100;
+ else if (strbeg("CDR4220", prod_ident))
+ usalp->dev = DEV_CDD_2000;
+
+ } else if (strbeg("PLEXTOR", vendor_info)) {
+ if (strbeg("CD-R PX-R24CS", prod_ident))
+ usalp->dev = DEV_RICOH_RO_1420C;
+
+ } else if (strbeg("RICOH", vendor_info)) {
+ if (strbeg("RO-1420C", prod_ident))
+ usalp->dev = DEV_RICOH_RO_1420C;
+ if (strbeg("RO1060C", prod_ident))
+ usalp->dev = DEV_RICOH_RO_1060C;
+
+ } else if (strbeg("SAF", vendor_info)) { /* Smart & Friendly */
+ if (strbeg("CD-R2004", prod_ident) ||
+ strbeg("CD-R2006 ", prod_ident))
+ usalp->dev = DEV_SONY_CDU_924;
+ else if (strbeg("CD-R2006PLUS", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ else if (strbeg("CD-RW226", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+ else if (strbeg("CD-R4012", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+
+ } else if (strbeg("SANYO", vendor_info)) {
+ if (strbeg("CD-WO CRD-R24S", prod_ident))
+ usalp->dev = DEV_CDD_521;
+
+ } else if (strbeg("SONY", vendor_info)) {
+ if (strbeg("CD-R CDU92", prod_ident) ||
+ strbeg("CD-R CDU94", prod_ident))
+ usalp->dev = DEV_SONY_CDU_924;
+
+ } else if (strbeg("TEAC", vendor_info)) {
+ if (strbeg("CD-R50S", prod_ident) ||
+ strbeg("CD-R55S", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+
+ } else if (strbeg("TRAXDATA", vendor_info) ||
+ strbeg("Traxdata", vendor_info)) {
+ if (strbeg("CDR4120", prod_ident))
+ usalp->dev = DEV_TEAC_CD_R50S;
+
+ } else if (strbeg("T.YUDEN", vendor_info)) {
+ if (strbeg("CD-WO EW-50", prod_ident))
+ usalp->dev = DEV_TYUDEN_EW50;
+
+ } else if (strbeg("WPI", vendor_info)) { /* Wearnes */
+ if (strbeg("CDR-632P", prod_ident))
+ usalp->dev = DEV_CDD_2600;
+
+ } else if (strbeg("YAMAHA", vendor_info)) {
+ if (strbeg("CDR10", prod_ident))
+ usalp->dev = DEV_YAMAHA_CDR_100;
+ if (strbeg("CDR200", prod_ident))
+ usalp->dev = DEV_YAMAHA_CDR_400;
+ if (strbeg("CDR400", prod_ident))
+ usalp->dev = DEV_YAMAHA_CDR_400;
+
+ } else if (strbeg("MATSHITA", vendor_info)) {
+ if (strbeg("CD-R CW-7501", prod_ident))
+ usalp->dev = DEV_MATSUSHITA_7501;
+ if (strbeg("CD-R CW-7502", prod_ident))
+ usalp->dev = DEV_MATSUSHITA_7502;
+ }
+ if (usalp->dev == DEV_UNKNOWN) {
+ /*
+ * We do not have Manufacturer strings for
+ * the following drives.
+ */
+ if (strbeg("CDS615E", prod_ident)) /* Olympus */
+ usalp->dev = DEV_SONY_CDU_924;
+ }
+ if (usalp->dev == DEV_UNKNOWN && inq->type == INQ_ROMD) {
+ BOOL cdrr = FALSE;
+ BOOL cdwr = FALSE;
+ BOOL cdrrw = FALSE;
+ BOOL cdwrw = FALSE;
+ BOOL dvd = FALSE;
+ BOOL dvdwr = FALSE;
+
+ usalp->dev = DEV_CDROM;
+
+ if (mmc_check(usalp, &cdrr, &cdwr, &cdrrw, &cdwrw,
+ &dvd, &dvdwr))
+ usalp->dev = DEV_MMC_CDROM;
+ if (cdwr)
+ usalp->dev = DEV_MMC_CDR;
+ if (cdwrw)
+ usalp->dev = DEV_MMC_CDRW;
+ if (dvd)
+ usalp->dev = DEV_MMC_DVD;
+ if (dvdwr)
+ usalp->dev = DEV_MMC_DVD_WR;
+ }
+ break;
+
+ case INQ_PROCD:
+ if (strbeg("BERTHOLD", vendor_info)) {
+ if (strbeg("", prod_ident))
+ usalp->dev = DEV_HRSCAN;
+ }
+ break;
+
+ case INQ_SCAN:
+ usalp->dev = DEV_MS300A;
+ break;
+ }
+ usalp->silent--;
+ if (!print)
+ return (TRUE);
+
+ if (usalp->dev == DEV_UNKNOWN && !got_inquiry) {
+#ifdef PRINT_INQ_ERR
+ usal_printerr(usalp);
+#endif
+ return (FALSE);
+ }
+
+ printinq(usalp, stdout);
+ return (TRUE);
+}
+
+void
+printinq(SCSI *usalp, FILE *f)
+{
+ register struct scsi_inquiry *inq = usalp->inq;
+
+ fprintf(f, "Device type : ");
+ usal_fprintdev(f, inq);
+ fprintf(f, "Version : %d\n", inq->ansi_version);
+ fprintf(f, "Response Format: %d\n", inq->data_format);
+ if (inq->data_format >= 2) {
+ fprintf(f, "Capabilities : ");
+ if (inq->aenc) fprintf(f, "AENC ");
+ if (inq->termiop) fprintf(f, "TERMIOP ");
+ if (inq->reladr) fprintf(f, "RELADR ");
+ if (inq->wbus32) fprintf(f, "WBUS32 ");
+ if (inq->wbus16) fprintf(f, "WBUS16 ");
+ if (inq->sync) fprintf(f, "SYNC ");
+ if (inq->linked) fprintf(f, "LINKED ");
+ if (inq->cmdque) fprintf(f, "CMDQUE ");
+ if (inq->softreset) fprintf(f, "SOFTRESET ");
+ fprintf(f, "\n");
+ }
+ if (inq->add_len >= 31 ||
+ inq->vendor_info[0] ||
+ inq->prod_ident[0] ||
+ inq->prod_revision[0]) {
+ fprintf(f, "Vendor_info : '%.8s'\n", inq->vendor_info);
+ fprintf(f, "Identification : '%.16s'\n", inq->prod_ident);
+ fprintf(f, "Revision : '%.4s'\n", inq->prod_revision);
+ }
+}
+
+void
+printdev(SCSI *usalp)
+{
+ printf("Device seems to be: ");
+
+ switch (usalp->dev) {
+
+ case DEV_UNKNOWN: printf("unknown"); break;
+ case DEV_ACB40X0: printf("Adaptec 4000/4010/4070"); break;
+ case DEV_ACB4000: printf("Adaptec 4000"); break;
+ case DEV_ACB4010: printf("Adaptec 4010"); break;
+ case DEV_ACB4070: printf("Adaptec 4070"); break;
+ case DEV_ACB5500: printf("Adaptec 5500"); break;
+ case DEV_ACB4520A: printf("Adaptec 4520A"); break;
+ case DEV_ACB4525: printf("Adaptec 4525"); break;
+ case DEV_MD21: printf("Emulex MD21"); break;
+ case DEV_MD23: printf("Emulex MD23"); break;
+ case DEV_NON_CCS_DSK: printf("Generic NON CCS Disk"); break;
+ case DEV_CCS_GENDISK: printf("Generic CCS Disk"); break;
+ case DEV_SONY_SMO: printf("Sony SMO-C501"); break;
+ case DEV_MT02: printf("Emulex MT02"); break;
+ case DEV_SC4000: printf("Sysgen SC4000"); break;
+ case DEV_RXT800S: printf("Maxtor RXT800S"); break;
+ case DEV_HRSCAN: printf("Berthold HR-Scanner"); break;
+ case DEV_MS300A: printf("Microtek MS300A"); break;
+
+ case DEV_CDROM: printf("Generic CD-ROM"); break;
+ case DEV_MMC_CDROM: printf("Generic mmc CD-ROM"); break;
+ case DEV_MMC_CDR: printf("Generic mmc CD-R"); break;
+ case DEV_MMC_CDRW: printf("Generic mmc CD-RW"); break;
+ case DEV_MMC_DVD: printf("Generic mmc2 DVD-ROM"); break;
+ case DEV_MMC_DVD_WR: printf("Generic mmc2 DVD-R/DVD-RW"); break;
+ case DEV_CDD_521_OLD: printf("Philips old CDD-521"); break;
+ case DEV_CDD_521: printf("Philips CDD-521"); break;
+ case DEV_CDD_522: printf("Philips CDD-522"); break;
+ case DEV_PCD_600: printf("Kodak PCD-600"); break;
+ case DEV_CDD_2000: printf("Philips CDD-2000"); break;
+ case DEV_CDD_2600: printf("Philips CDD-2600"); break;
+ case DEV_YAMAHA_CDR_100:printf("Yamaha CDR-100"); break;
+ case DEV_YAMAHA_CDR_400:printf("Yamaha CDR-400"); break;
+ case DEV_PLASMON_RF_4100:printf("Plasmon RF-4100"); break;
+ case DEV_SONY_CDU_924: printf("Sony CDU-924S"); break;
+ case DEV_RICOH_RO_1060C:printf("Ricoh RO-1060C"); break;
+ case DEV_RICOH_RO_1420C:printf("Ricoh RO-1420C"); break;
+ case DEV_TEAC_CD_R50S: printf("Teac CD-R50S"); break;
+ case DEV_MATSUSHITA_7501:printf("Matsushita CW-7501"); break;
+ case DEV_MATSUSHITA_7502:printf("Matsushita CW-7502"); break;
+
+ case DEV_PIONEER_DW_S114X: printf("Pioneer DW-S114X"); break;
+ case DEV_PIONEER_DVDR_S101:printf("Pioneer DVD-R S101"); break;
+
+ default: printf("Missing Entry for dev %d",
+ usalp->dev); break;
+
+ }
+ printf(".\n");
+
+}
+
+BOOL
+do_inquiry(SCSI *usalp, int print)
+{
+ if (getdev(usalp, print)) {
+ if (print)
+ printdev(usalp);
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+BOOL
+recovery_needed(SCSI *usalp, cdr_t *dp)
+{
+ int err;
+ register struct usal_cmd *scmd = usalp->scmd;
+
+ usalp->silent++;
+ err = test_unit_ready(usalp);
+ usalp->silent--;
+
+ if (err >= 0)
+ return (FALSE);
+ else if (scmd->error >= SCG_FATAL) /* nicht selektierbar */
+ return (FALSE);
+
+ if (scmd->sense.code < 0x70) /* non extended Sense */
+ return (FALSE);
+
+ /* XXX Old Philips code */
+ return (((struct scsi_ext_sense *)&scmd->sense)->sense_code == 0xD0);
+}
+
+int
+scsi_load(SCSI *usalp, cdr_t *dp)
+{
+ int key;
+ int code;
+
+ if ((dp->cdr_flags & CDR_CADDYLOAD) == 0) {
+ if (scsi_start_stop_unit(usalp, 1, 1, dp && (dp->cdr_cmdflags&F_IMMED)) >= 0)
+ return (0);
+ }
+
+ if (wait_unit_ready(usalp, 60))
+ return (0);
+
+ key = usal_sense_key(usalp);
+ code = usal_sense_code(usalp);
+
+ if (key == SC_NOT_READY && (code == 0x3A || code == 0x30)) {
+ errmsgno(EX_BAD, "Cannot load media with %s drive!\n",
+ (dp->cdr_flags & CDR_CADDYLOAD) ? "caddy" : "this");
+ errmsgno(EX_BAD, "Try to load media by hand.\n");
+ }
+ return (-1);
+}
+
+int
+scsi_unload(SCSI *usalp, cdr_t *dp)
+{
+ return (scsi_start_stop_unit(usalp, 0, 1, dp && (dp->cdr_cmdflags&F_IMMED)));
+}
+
+int
+scsi_cdr_write(SCSI *usalp,
+ caddr_t bp /* address of buffer */,
+ long sectaddr /* disk address (sector) to put */,
+ long size /* number of bytes to transfer */,
+ int blocks /* sector count */,
+ BOOL islast /* last write for track */)
+{
+ return (write_xg1(usalp, bp, sectaddr, size, blocks));
+}
+
+struct cd_mode_page_2A *
+mmc_cap(SCSI *usalp, Uchar *modep)
+{
+ int len;
+ int val;
+ Uchar mode[0x100];
+ struct cd_mode_page_2A *mp;
+ struct cd_mode_page_2A *mp2;
+
+
+retry:
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ if (!get_mode_params(usalp, 0x2A, "CD capabilities",
+ mode, (Uchar *)0, (Uchar *)0, (Uchar *)0, &len)) {
+
+ if (usal_sense_key(usalp) == SC_NOT_READY) {
+ if (wait_unit_ready(usalp, 60))
+ goto retry;
+ }
+ return (NULL); /* Pre SCSI-3/mmc drive */
+ }
+
+ if (len == 0) /* Pre SCSI-3/mmc drive */
+ return (NULL);
+
+ mp = (struct cd_mode_page_2A *)
+ (mode + sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len);
+
+ /*
+ * Do some heuristics against pre SCSI-3/mmc VU page 2A
+ * We should test for a minimum p_len of 0x14, but some
+ * buggy CD-ROM readers ommit the write speed values.
+ */
+ if (mp->p_len < 0x10)
+ return (NULL);
+
+ val = a_to_u_2_byte(mp->max_read_speed);
+ if (val != 0 && val < 176)
+ return (NULL);
+
+ val = a_to_u_2_byte(mp->cur_read_speed);
+ if (val != 0 && val < 176)
+ return (NULL);
+
+ len -= sizeof (struct scsi_mode_header) +
+ ((struct scsi_mode_header *)mode)->blockdesc_len;
+ if (modep)
+ mp2 = (struct cd_mode_page_2A *)modep;
+ else
+ mp2 = malloc(len);
+ if (mp2)
+ movebytes(mp, mp2, len);
+
+ return (mp2);
+}
+
+void
+mmc_getval(struct cd_mode_page_2A *mp,
+ BOOL *cdrrp /* CD ROM */,
+ BOOL *cdwrp /* CD-R writer */,
+ BOOL *cdrrwp /* CD-RW reader */,
+ BOOL *cdwrwp /* CD-RW writer */,
+ BOOL *dvdp /* DVD reader */,
+ BOOL *dvdwp /* DVD writer */)
+{
+ BOOL isdvd; /* Any DVD reader */
+ BOOL isdvd_wr; /* DVD writer (R / RAM) */
+ BOOL iscd_wr; /* CD writer */
+
+ iscd_wr = (mp->cd_r_write != 0) || /* SCSI-3/mmc CD-R */
+ (mp->cd_rw_write != 0); /* SCSI-3/mmc CD-RW */
+
+ if (cdrrp)
+ *cdrrp = (mp->cd_r_read != 0); /* SCSI-3/mmc CD */
+ if (cdwrp)
+ *cdwrp = (mp->cd_r_write != 0); /* SCSI-3/mmc CD-R */
+
+ if (cdrrwp)
+ *cdrrwp = (mp->cd_rw_read != 0); /* SCSI-3/mmc CD */
+ if (cdwrwp)
+ *cdwrwp = (mp->cd_rw_write != 0); /* SCSI-3/mmc CD-RW */
+
+ isdvd = /* SCSI-3/mmc2 DVD */
+ (mp->dvd_ram_read + mp->dvd_r_read +
+ mp->dvd_rom_read) != 0;
+
+ isdvd_wr = /* SCSI-3/mmc2 DVD writer*/
+ (mp->dvd_ram_write + mp->dvd_r_write) != 0;
+
+ if (dvdp)
+ *dvdp = isdvd;
+ if (dvdwp)
+ *dvdwp = isdvd_wr;
+}
+
+BOOL
+is_mmc(SCSI *usalp, BOOL *cdwp, BOOL *dvdwp)
+{
+ BOOL cdwr = FALSE;
+ BOOL cdwrw = FALSE;
+
+ if (cdwp)
+ *cdwp = FALSE;
+ if (dvdwp)
+ *dvdwp = FALSE;
+
+ if (!mmc_check(usalp, NULL, &cdwr, NULL, &cdwrw, NULL, dvdwp))
+ return (FALSE);
+
+ if (cdwp)
+ *cdwp = cdwr | cdwrw;
+
+ return (TRUE);
+}
+
+BOOL
+mmc_check(SCSI *usalp,
+ BOOL *cdrrp /* CD ROM */,
+ BOOL *cdwrp /* CD-R writer */,
+ BOOL *cdrrwp /* CD-RW reader */,
+ BOOL *cdwrwp /* CD-RW writer */,
+ BOOL *dvdp /* DVD reader */,
+ BOOL *dvdwp /* DVD writer */)
+{
+ Uchar mode[0x100];
+ BOOL was_atapi;
+ struct cd_mode_page_2A *mp;
+
+ if (usalp->inq->type != INQ_ROMD)
+ return (FALSE);
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ was_atapi = allow_atapi(usalp, TRUE);
+ usalp->silent++;
+ mp = mmc_cap(usalp, mode);
+ usalp->silent--;
+ allow_atapi(usalp, was_atapi);
+ if (mp == NULL)
+ return (FALSE);
+
+ mmc_getval(mp, cdrrp, cdwrp, cdrrwp, cdwrwp, dvdp, dvdwp);
+
+ return (TRUE); /* Generic SCSI-3/mmc CD */
+}
+
+static void
+print_speed(char *fmt, int val)
+{
+ printf(" %s: %5d kB/s", fmt, val);
+ printf(" (CD %3ux,", val/176);
+ printf(" DVD %2ux)\n", val/1385);
+}
+
+#define DOES(what, flag) printf(" Does %s%s\n", flag?"":"not ", what)
+#define IS(what, flag) printf(" Is %s%s\n", flag?"":"not ", what)
+#define VAL(what, val) printf(" %s: %d\n", what, val[0]*256 + val[1])
+#define SVAL(what, val) printf(" %s: %s\n", what, val)
+
+void
+print_capabilities(SCSI *usalp)
+{
+ BOOL was_atapi;
+ Uchar mode[0x100];
+ struct cd_mode_page_2A *mp;
+static const char *bclk[4] = {"32", "16", "24", "24 (I2S)"};
+static const char *load[8] = {"caddy", "tray", "pop-up", "reserved(3)",
+ "disc changer", "cartridge changer",
+ "reserved(6)", "reserved(7)" };
+static const char *rotctl[4] = {"CLV/PCAV", "CAV", "reserved(2)", "reserved(3)"};
+
+
+ if (usalp->inq->type != INQ_ROMD)
+ return;
+
+ fillbytes((caddr_t)mode, sizeof (mode), '\0');
+
+ was_atapi = allow_atapi(usalp, TRUE); /* Try to switch to 10 byte mode cmds */
+ usalp->silent++;
+ mp = mmc_cap(usalp, mode);
+ usalp->silent--;
+ allow_atapi(usalp, was_atapi);
+ if (mp == NULL)
+ return;
+
+ printf("\nDrive capabilities, per");
+ if (mp->p_len >= 28)
+ printf(" MMC-3");
+ else if (mp->p_len >= 24)
+ printf(" MMC-2");
+ else
+ printf(" MMC");
+ printf(" page 2A:\n\n");
+
+ DOES("read CD-R media", mp->cd_r_read);
+ DOES("write CD-R media", mp->cd_r_write);
+ DOES("read CD-RW media", mp->cd_rw_read);
+ DOES("write CD-RW media", mp->cd_rw_write);
+ DOES("read DVD-ROM media", mp->dvd_rom_read);
+ DOES("read DVD-R media", mp->dvd_r_read);
+ DOES("write DVD-R media", mp->dvd_r_write);
+ DOES("read DVD-RAM media", mp->dvd_ram_read);
+ DOES("write DVD-RAM media", mp->dvd_ram_write);
+ DOES("support test writing", mp->test_write);
+ printf("\n");
+ DOES("read Mode 2 Form 1 blocks", mp->mode_2_form_1);
+ DOES("read Mode 2 Form 2 blocks", mp->mode_2_form_2);
+ DOES("read digital audio blocks", mp->cd_da_supported);
+ if (mp->cd_da_supported)
+ DOES("restart non-streamed digital audio reads accurately", mp->cd_da_accurate);
+ DOES("support Buffer-Underrun-Free recording", mp->BUF);
+ DOES("read multi-session CDs", mp->multi_session);
+ DOES("read fixed-packet CD media using Method 2", mp->method2);
+ DOES("read CD bar code", mp->read_bar_code);
+ DOES("read R-W subcode information", mp->rw_supported);
+ if (mp->rw_supported)
+ DOES("return R-W subcode de-interleaved and error-corrected", mp->rw_deint_corr);
+ DOES("read raw P-W subcode data from lead in", mp->pw_in_lead_in);
+ DOES("return CD media catalog number", mp->UPC);
+ DOES("return CD ISRC information", mp->ISRC);
+ DOES("support C2 error pointers", mp->c2_pointers);
+ DOES("deliver composite A/V data", mp->composite);
+ printf("\n");
+ DOES("play audio CDs", mp->audio_play);
+ if (mp->audio_play) {
+ VAL("Number of volume control levels", mp->num_vol_levels);
+ DOES("support individual volume control setting for each channel", mp->sep_chan_vol);
+ DOES("support independent mute setting for each channel", mp->sep_chan_mute);
+ DOES("support digital output on port 1", mp->digital_port_1);
+ DOES("support digital output on port 2", mp->digital_port_2);
+ if (mp->digital_port_1 || mp->digital_port_2) {
+ DOES("send digital data LSB-first", mp->LSBF);
+ DOES("set LRCK high for left-channel data", mp->RCK);
+ DOES("have valid data on falling edge of clock", mp->BCK);
+ SVAL("Length of data in BCLKs", bclk[mp->length]);
+ }
+ }
+ printf("\n");
+ SVAL("Loading mechanism type", load[mp->loading_type]);
+ DOES("support ejection of CD via START/STOP command", mp->eject);
+ DOES("lock media on power up via prevent jumper", mp->prevent_jumper);
+ DOES("allow media to be locked in the drive via PREVENT/ALLOW command", mp->lock);
+ IS("currently in a media-locked state", mp->lock_state);
+ DOES("support changing side of disk", mp->side_change);
+ DOES("have load-empty-slot-in-changer feature", mp->sw_slot_sel);
+ DOES("support Individual Disk Present feature", mp->disk_present_rep);
+ printf("\n");
+ print_speed("Maximum read speed", a_to_u_2_byte(mp->max_read_speed));
+ print_speed("Current read speed", a_to_u_2_byte(mp->cur_read_speed));
+ print_speed("Maximum write speed", a_to_u_2_byte(mp->max_write_speed));
+ if (mp->p_len >= 28)
+ print_speed("Current write speed", a_to_u_2_byte(mp->v3_cur_write_speed));
+ else
+ print_speed("Current write speed", a_to_u_2_byte(mp->cur_write_speed));
+ if (mp->p_len >= 28) {
+ SVAL("Rotational control selected", rotctl[mp->rot_ctl_sel]);
+ }
+ VAL("Buffer size in KB", mp->buffer_size);
+
+ if (mp->p_len >= 24) {
+ VAL("Copy management revision supported", mp->copy_man_rev);
+ }
+
+ if (mp->p_len >= 28) {
+ struct cd_wr_speed_performance *pp;
+ Uint ndesc;
+ Uint i;
+ Uint n;
+
+ ndesc = a_to_u_2_byte(mp->num_wr_speed_des);
+ pp = mp->wr_speed_des;
+ printf(" Number of supported write speeds: %d\n", ndesc);
+ for (i = 0; i < ndesc; i++, pp++) {
+ printf(" Write speed # %d:", i);
+ n = a_to_u_2_byte(pp->wr_speed_supp);
+ printf(" %5d kB/s", n);
+ printf(" %s", rotctl[pp->rot_ctl_sel]);
+ printf(" (CD %3ux,", n/176);
+ printf(" DVD %2ux)\n", n/1385);
+ }
+ }
+
+ /* Generic SCSI-3/mmc CD */
+}