📄 scsi_cdr.c
字号:
/* @(#)scsi_cdr.c 1.56 98/10/18 Copyright 1995 J. Schilling */#ifndef lintstatic char sccsid[] = "@(#)scsi_cdr.c 1.56 98/10/18 Copyright 1995 J. Schilling";#endif/* * SCSI command functions for cdrecord * * Copyright (c) 1995 J. Schilling *//* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * 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, 675 Mass Ave, Cambridge, MA 02139, 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 <stdlib.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <utypes.h>#include <btorder.h>#include <scgio.h>#include <scsidefs.h>#include <scsireg.h>#include "cdrecord.h"#include "scsitransp.h"#define strbeg(s1,s2) (strstr((s2), (s1)) == (s2))struct scg_cmd scmd;struct scsi_inquiry inq;struct scsi_capacity cap = { 0, 2048 };/*struct scsi_capacity cap = { 0, 2352 };*/extern int scsibus;extern int target;extern int lun;extern int silent;extern int debug;extern int verbose;extern int lverbose;EXPORT int open_scsi __PR((char *scsidev, int timeout, int be_verbose));LOCAL int scsi_scandev __PR((char *devp, int *xp1, int *xp2, int *xp3));EXPORT void scsi_settimeout __PR((int timeout));EXPORT BOOL unit_ready __PR((void));EXPORT BOOL wait_unit_ready __PR((int secs));EXPORT int test_unit_ready __PR((void));EXPORT int rezero_unit __PR((void));EXPORT int request_sense __PR((void));EXPORT int inquiry __PR((caddr_t, int));EXPORT int read_capacity __PR((void));EXPORT int scsi_load_unload __PR((int));EXPORT int load_unload_philips __PR((int));EXPORT int scsi_prevent_removal __PR((int));EXPORT int scsi_start_stop_unit __PR((int, int));EXPORT int scsi_set_speed __PR((int readspeed, int writespeed));EXPORT int qic02 __PR((int));EXPORT int write_xg0 __PR((caddr_t, long, long, int));EXPORT int write_xg1 __PR((caddr_t, long, long, int));EXPORT int write_xg5 __PR((caddr_t, long, long, int));EXPORT int write_track __PR((long, int));EXPORT int scsi_flush_cache __PR((void));EXPORT int read_toc __PR((caddr_t, int, int, int, int));EXPORT int read_toc_philips __PR((caddr_t, int, int, int, int));EXPORT int read_header __PR((caddr_t, long, int, int));EXPORT int read_disk_info __PR((caddr_t, int));EXPORT int read_track_info __PR((caddr_t, int, int));EXPORT int read_track_info_philips __PR((caddr_t, int, int));EXPORT int close_track_philips __PR((int track, track_t *trackp));EXPORT int fixation __PR((int, int, int, int tracks, track_t *trackp));EXPORT int scsi_close_tr_session __PR((int type, int track));EXPORT int scsi_blank __PR((long addr, int blanktype));EXPORT int recover __PR((int));EXPORT int first_writable_addr __PR((long *, int, int, int, int));EXPORT int reserve_track __PR((unsigned long));EXPORT BOOL allow_atapi __PR((BOOL new));EXPORT int mode_select __PR((u_char *, int, int, int));EXPORT int mode_sense __PR((u_char *dp, int cnt, int page, int pcf));EXPORT int mode_select_sg0 __PR((u_char *, int, int, int));EXPORT int mode_sense_sg0 __PR((u_char *dp, int cnt, int page, int pcf));EXPORT int mode_select_g0 __PR((u_char *, int, int, int));EXPORT int mode_select_g1 __PR((u_char *, int, int, int));EXPORT int mode_sense_g0 __PR((u_char *dp, int cnt, int page, int pcf));EXPORT int mode_sense_g1 __PR((u_char *dp, int cnt, int page, int pcf));EXPORT int speed_select_yamaha __PR((int speed, int dummy));EXPORT int speed_select_philips __PR((int speed, int dummy));EXPORT int write_track_info __PR((int));EXPORT int read_tochdr __PR((cdr_t *, int *, int *));EXPORT int read_trackinfo __PR((int, long *, struct msf *, int *, int *, int *));EXPORT int read_B0 __PR((BOOL isbcd, long *b0p, long *lop));EXPORT int read_session_offset __PR((long *));EXPORT int read_session_offset_philips __PR((long *));EXPORT int sense_secsize __PR((int current));EXPORT int select_secsize __PR((int));EXPORT BOOL is_cddrive __PR((void));EXPORT BOOL is_unknown_dev __PR((void));EXPORT int read_scsi __PR((caddr_t, long, int));EXPORT int read_g0 __PR((caddr_t, long, int));EXPORT int read_g1 __PR((caddr_t, long, int));EXPORT BOOL getdev __PR((BOOL));EXPORT void printdev __PR((void));EXPORT BOOL do_inquiry __PR((BOOL));EXPORT BOOL recovery_needed __PR((void));EXPORT int scsi_load __PR((void));EXPORT int scsi_unload __PR((void));EXPORT int scsi_cdr_write __PR((caddr_t bp, long sectaddr, long size, int blocks, BOOL islast));EXPORT struct cd_mode_page_2A * mmc_cap __PR((u_char *modep));EXPORT void mmc_getval __PR((struct cd_mode_page_2A *mp, BOOL *cdrrp, BOOL *cdwrp, BOOL *cdrrwp, BOOL *cdwrwp, BOOL *dvdp));EXPORT BOOL is_mmc __PR((BOOL *dvdp));EXPORT BOOL mmc_check __PR((BOOL *cdrrp, BOOL *cdwrp, BOOL *cdrrwp, BOOL *cdwrwp, BOOL *dvdp));EXPORT void print_capabilities __PR((void));/* * Open a SCSI device. * * Possible syntax is: * * Preferred: * dev=target,lun / dev=scsibus,target,lun * * Needed on some systems: * dev=devicename:target,lun / dev=devicename:scsibus,target,lun * * On systems that don't support SCSI Bus scanning this syntax helps: * dev=devicename:@ / dev=devicename:@,lun * or dev=devicename (undocumented) * * NOTE: As the 'lun' is part of the SCSI command descriptor block, it * must always be known. If the OS cannot map it, it must be * specified on command line. */EXPORT intopen_scsi(scsidev, timeout, be_verbose) char *scsidev; int timeout; int be_verbose;{ char devname[256]; char *devp = NULL; int x1, x2, x3; int n = 0; extern int deftimeout; if (timeout >= 0) deftimeout = timeout; devname[0] = '\0'; if (scsidev != NULL) { if ((devp = strchr(scsidev, ':')) == NULL) { if (strchr(scsidev, ',') == NULL) { /* Notation form: 'devname' (undocumented) */ /* Fetch bus/tgt/lun values from OS */ n = -1; lun = -2; /* Lun must be known */ strncpy(devname, scsidev, sizeof(devname)-1); devname[sizeof(devname)-1] = '\0'; } else { /* Basic notation form: 'bus,tgt,lun' */ devp = scsidev; } } else { /* Notation form: 'devname:bus,tgt,lun'/'devname:@' */ x1 = devp - scsidev; if (x1 >= sizeof(devname)) x1 = sizeof(devname)-1; strncpy(devname, scsidev, x1); devname[x1] = '\0'; devp++; /* Check for a notation in the form 'devname:@' */ if (devp[0] == '@') { if (devp[1] == '\0') { lun = -2; } else if (devp[1] == ',') { if (*astoi(&devp[2], &lun) != '\0') return (-1); } n = -1; devp = NULL; } } } if (devp != NULL) { n = scsi_scandev(devp, &x1, &x2, &x3); if (n < 0) { errno = EINVAL; return (-1); } } if (n == 3) { /* Got bus,target,lun */ scsibus = x1; target = x2; lun = x3; } else if (n == 2) { /* Got target,lun */ scsibus = 0; target = x1; lun = x2; } else if (n == -1) { /* Got device:@, fetch bus/lun from OS */ scsibus = target = -2; } else if (devp != NULL) { printf("WARNING: device not valid, trying to use default target...\n"); scsibus = 0; target = 6; lun = 0; } if (be_verbose && scsidev != NULL) { printf("scsidev: '%s'\n", scsidev); if (devname[0] != '\0') printf("devname: '%s'\n", devname); printf("scsibus: %d target: %d lun: %d\n", scsibus, target, lun); } return (scsi_open(devname, scsibus, target, lun));}/* * Convert target,lun or scsibus,target,lun syntax. * Check for bad syntax and invalid values. * This is definitely better than using scanf() as it checks for syntax errors. */LOCAL intscsi_scandev(devp, xp1, xp2, xp3) char *devp; int *xp1; int *xp2; int *xp3;{ int n = 0; *xp1 = *xp2 = *xp3 = 0; if (*devp != '\0') { devp = astoi(devp, xp1); if (*devp == ',') { devp++; n++; } else { return (-1); } } if (*devp != '\0') { devp = astoi(devp, xp2); if (*devp == ',' || *devp == '\0') { if (*devp != '\0') devp++; n++; } else { return (-1); } } if (*devp != '\0') { devp = astoi(devp, xp3); if (*devp == '\0') { n++; } else { return (-1); } } if (*xp1 < 0 || *xp2 < 0 || *xp3 < 0) return (-1); return (n);}EXPORT voidscsi_settimeout(timeout) int timeout;{ extern int deftimeout; deftimeout = timeout / 100;}EXPORT BOOLunit_ready(){ if (test_unit_ready() >= 0) /* alles OK */ return (TRUE); else if (scmd.error >= SCG_FATAL) /* nicht selektierbar */ return (FALSE); if (scmd.sense.code < 0x70) { /* non extended Sense */ if (scmd.sense.code == 0x04) /* NOT_READY */ return (FALSE); return (TRUE); } if (((struct scsi_ext_sense *)&scmd.sense)->key == SC_UNIT_ATTENTION) { if (test_unit_ready() >= 0) /* alles OK */ return (TRUE); } /* FALSE wenn NOT_READY */ return (((struct scsi_ext_sense *)&scmd.sense)->key != SC_NOT_READY);}EXPORT BOOLwait_unit_ready(secs) int secs;{ int i; int c; int k; int ret; silent++; ret = test_unit_ready(); /* eat up unit attention */ silent--; if (ret >= 0) /* success that's enough */ return (TRUE); silent++; for (i=0; i < secs && (ret = test_unit_ready()) < 0; i++) { if (scmd.scb.busy != 0) { sleep(1); continue; } c = scsi_sense_code(); k = scsi_sense_key(); if (k == SC_NOT_READY && (c == 0x3A || c == 0x30)) { scsiprinterr("test_unit_ready"); silent--; return (FALSE); } sleep(1); } silent--; if (ret < 0) return (FALSE); return (TRUE);}EXPORT inttest_unit_ready(){ fillbytes((caddr_t)&scmd, sizeof(scmd), '\0'); scmd.addr = (caddr_t)0; scmd.size = 0; scmd.flags = SCG_DISRE_ENA | (silent ? SCG_SILENT:0); scmd.cdb_len = SC_G0_CDBLEN; scmd.sense_len = CCS_SENSE_LEN; scmd.target = target; scmd.cdb.g0_cdb.cmd = SC_TEST_UNIT_READY; scmd.cdb.g0_cdb.lun = lun; return (scsicmd("test unit ready"));}EXPORT intrezero_unit(){ 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.target = target; scmd.cdb.g0_cdb.cmd = SC_REZERO_UNIT; scmd.cdb.g0_cdb.lun = lun; return (scsicmd("rezero unit"));}EXPORT intrequest_sense(){ char sensebuf[CCS_SENSE_LEN]; 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.target = target; scmd.cdb.g0_cdb.cmd = SC_REQUEST_SENSE; scmd.cdb.g0_cdb.lun = lun; scmd.cdb.g0_cdb.count = CCS_SENSE_LEN; if (scsicmd("request_sense") < 0) return (-1); scsiprsense((u_char *)sensebuf, CCS_SENSE_LEN - scmd.resid); return (0);}EXPORT intinquiry(bp, cnt) caddr_t bp; int cnt;{ 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.target = target; scmd.cdb.g0_cdb.cmd = SC_INQUIRY; scmd.cdb.g0_cdb.lun = lun; scmd.cdb.g0_cdb.count = cnt; if (scsicmd("inquiry") < 0) return (-1); if (verbose) scsiprbytes("Inquiry Data :", (u_char *)bp, cnt - scmd.resid); return (0);}EXPORT intread_capacity(){ fillbytes((caddr_t)&scmd, sizeof(scmd), '\0'); scmd.addr = (caddr_t)∩ scmd.size = sizeof(cap); scmd.flags = SCG_RECV_DATA|SCG_DISRE_ENA; scmd.cdb_len = SC_G1_CDBLEN; scmd.sense_len = CCS_SENSE_LEN; scmd.target = target; scmd.cdb.g1_cdb.cmd = 0x25; /* Read Capacity */ scmd.cdb.g1_cdb.lun = lun; g1_cdblen(&scmd.cdb.g1_cdb, 0); /* Full Media */ if (scsicmd("read capacity") < 0) { return (-1); } else { long kb; long mb; long prmb; double dkb; long cbsize; long cbaddr; cbsize = a_to_u_long(&cap.c_bsize); cbaddr = a_to_u_long(&cap.c_baddr); cap.c_bsize = cbsize; cap.c_baddr = cbaddr; if (silent) return (0); dkb = (cap.c_baddr+1.0) * (cap.c_bsize/1024.0); kb = dkb; mb = dkb / 1024.0; prmb = dkb / 1000.0 * 1.024; printf("Capacity: %ld Blocks = %ld kBytes = %ld MBytes = %ld prMB\n", cap.c_baddr+1, kb, mb, prmb); printf("Sectorsize: %ld Bytes\n", cap.c_bsize); } return (0);}EXPORT intscsi_load_unload(load) int load;{ 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.target = target; scmd.cdb.g5_cdb.cmd = 0xA6; scmd.cdb.g5_cdb.lun = lun; scmd.cdb.g5_cdb.addr[1] = load?3:2; scmd.cdb.g5_cdb.count[2] = 0; /* slot # */ if (scsicmd("medium load/unload") < 0) return (-1); return (0);}EXPORT intload_unload_philips(load) int load;{ 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.target = target; scmd.cdb.g1_cdb.cmd = 0xE7; scmd.cdb.g1_cdb.lun = lun; scmd.cdb.g1_cdb.count[1] = !load; if (scsicmd("medium load/unload") < 0) return (-1); return (0);}EXPORT intscsi_prevent_removal(prevent) int prevent;{ 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.target = target; scmd.cdb.g0_cdb.cmd = 0x1E; scmd.cdb.g0_cdb.lun = lun; scmd.cdb.g0_cdb.count = prevent & 1; if (scsicmd("prevent/allow medium removal") < 0) return (-1); return (0);}EXPORT intscsi_start_stop_unit(flg, loej) int flg; int loej;{ 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.target = target; scmd.cdb.g0_cdb.cmd = 0x1B; /* Start Stop Unit */ scmd.cdb.g0_cdb.lun = lun; scmd.cdb.g0_cdb.count = (flg ? 1:0) | (loej ? 2:0); return (scsicmd("start/stop unit"));}EXPORT intscsi_set_speed(readspeed, writespeed) int readspeed; int writespeed;{ 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.target = target; scmd.cdb.g5_cdb.cmd = 0xBB; scmd.cdb.g5_cdb.lun = lun; i_to_short(&scmd.cdb.g5_cdb.addr[0], readspeed); i_to_short(&scmd.cdb.g5_cdb.addr[2], writespeed); if (scsicmd("set cd speed") < 0) return (-1); return (0);}EXPORT intqic02(cmd) int cmd;{ 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.target = target; scmd.cdb.g0_cdb.cmd = 0x0D; /* qic02 Sysgen SC4000 */ scmd.cdb.g0_cdb.lun = lun; scmd.cdb.g0_cdb.mid_addr = cmd; return (scsicmd("qic 02"));}EXPORT intwrite_xg0(bp, addr, size, cnt) caddr_t bp; /* address of buffer */ long addr; /* disk address (sector) to put */ long size; /* number of bytes to transfer */ int cnt; /* sectorcount */{ 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.target = target; scmd.cdb.g0_cdb.cmd = SC_WRITE; scmd.cdb.g0_cdb.lun = lun; g0_cdbaddr(&scmd.cdb.g0_cdb, addr); scmd.cdb.g0_cdb.count = cnt; if (scsicmd("write_g0") < 0) return (-1); return (size - scmd.resid);}EXPORT intwrite_xg1(bp, addr, size, cnt) caddr_t bp; /* address of buffer */ long addr; /* disk address (sector) to put */ long size; /* number of bytes to transfer */ int cnt; /* sectorcount */{ 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.target = target; scmd.cdb.g1_cdb.cmd = SC_EWRITE; scmd.cdb.g1_cdb.lun = lun; g1_cdbaddr(&scmd.cdb.g1_cdb, addr); g1_cdblen(&scmd.cdb.g1_cdb, cnt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -