c88503add2
cdparanoia-alpha9.8-22.src.rpm
1944 lines
56 KiB
Diff
1944 lines
56 KiB
Diff
diff --exclude CVS -u -N -r cdparanoia-III-alpha9.8/interface/cdda_interface.h paranoia-III/interface/cdda_interface.h
|
|
--- cdparanoia-III-alpha9.8/interface/cdda_interface.h 2004-02-21 13:16:47.000000000 -0500
|
|
+++ cdparanoia-III-alpha9.8/interface/cdda_interface.h 2004-02-25 21:42:15.000000000 -0500
|
|
@@ -99,10 +99,46 @@
|
|
|
|
} cdrom_drive;
|
|
|
|
+/* buffers for use with the scsi code. d->sg_buffer is unused,
|
|
+ and d->sg points to this struct. We can't really change struct
|
|
+ cdrom_drive without breaking binary compatibility, so we do this
|
|
+ instead. */
|
|
+struct sg_info {
|
|
+#ifdef SG_IO
|
|
+ struct sg_io_hdr *hdr;
|
|
+#else
|
|
+ struct sg_header *hdr;
|
|
+#endif
|
|
+
|
|
+ char *cmdp;
|
|
+ ssize_t cmd_len;
|
|
+ ssize_t cmdp_buffer_len;
|
|
+
|
|
+ char *dxferp;
|
|
+ ssize_t dxferp_buffer_len;
|
|
+ ssize_t dxferp_max_buffer_len;
|
|
+
|
|
+ unsigned char bytefill;
|
|
+ int bytecheck;
|
|
+
|
|
+ int in_size;
|
|
+ int out_size;
|
|
+
|
|
+ int (*handle_scsi_cmd)(struct cdrom_drive *d);
|
|
+ void (*setup_scsi_cmd)(struct cdrom_drive *d,
|
|
+ char *cmdp, unsigned int cmd_len,
|
|
+ unsigned int in_size, unsigned int out_size);
|
|
+};
|
|
+
|
|
+
|
|
#define IS_AUDIO(d,i) (!(d->disc_toc[i].bFlags & 0x04))
|
|
|
|
/******** Identification/autosense functions */
|
|
|
|
+#ifdef SG_IO
|
|
+extern int check_fd_sgio(int fd);
|
|
+#endif
|
|
+
|
|
extern cdrom_drive *cdda_find_a_cdrom(int messagedest, char **message);
|
|
extern cdrom_drive *cdda_identify(const char *device, int messagedest,
|
|
char **message);
|
|
diff --exclude CVS -u -N -r cdparanoia-III-alpha9.8/interface/interface.c paranoia-III/interface/interface.c
|
|
--- cdparanoia-III-alpha9.8/interface/interface.c 2004-02-21 13:16:49.000000000 -0500
|
|
+++ cdparanoia-III-alpha9.8/interface/interface.c 2004-02-25 11:17:37.000000000 -0500
|
|
@@ -30,7 +30,7 @@
|
|
|
|
_clean_messages(d);
|
|
if(d->cdda_device_name)free(d->cdda_device_name);
|
|
- if(d->ioctl_device_name)free(d->ioctl_device_name);
|
|
+ if(d->ioctl_device_name && d->ioctl_device_name!=d->cdda_device_name)free(d->ioctl_device_name);
|
|
if(d->drive_model)free(d->drive_model);
|
|
if(d->cdda_fd!=-1)close(d->cdda_fd);
|
|
if(d->ioctl_fd!=-1 && d->ioctl_fd!=d->cdda_fd)close(d->ioctl_fd);
|
|
diff --exclude CVS -u -N -r cdparanoia-III-alpha9.8/interface/scan_devices.c paranoia-III/interface/scan_devices.c
|
|
--- cdparanoia-III-alpha9.8/interface/scan_devices.c 2004-02-21 13:16:51.000000000 -0500
|
|
+++ cdparanoia-III-alpha9.8/interface/scan_devices.c 2004-02-26 19:26:15.000000000 -0500
|
|
@@ -14,8 +14,8 @@
|
|
#include <pwd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
-#include "cdda_interface.h"
|
|
#include "low_interface.h"
|
|
+#include "cdda_interface.h"
|
|
#include "common_interface.h"
|
|
#include "utils.h"
|
|
|
|
@@ -50,6 +50,8 @@
|
|
"/dev/gscd",
|
|
"/dev/optcd",NULL};
|
|
|
|
+extern void sg2_init_sg_info(cdrom_drive *d);
|
|
+extern void sgio_init_sg_info(cdrom_drive *d);
|
|
/* Functions here look for a cdrom drive; full init of a drive type
|
|
happens in interface.c */
|
|
|
|
@@ -117,8 +119,13 @@
|
|
}
|
|
#endif
|
|
|
|
- d=cdda_identify_cooked(device,messagedest,messages);
|
|
+#ifdef SG_IO
|
|
+ d=cdda_identify_scsi(device,NULL,messagedest,messages);
|
|
+ if(!d)d=cdda_identify_cooked(device,messagedest,messages);
|
|
+#else
|
|
if(!d)d=cdda_identify_scsi(device,NULL,messagedest,messages);
|
|
+ d=cdda_identify_cooked(device,messagedest,messages);
|
|
+#endif
|
|
|
|
#ifdef CDDA_TEST
|
|
if(!d)d=cdda_identify_test(device,messagedest,messages);
|
|
@@ -412,17 +419,19 @@
|
|
"\nFound an accessible SCSI CDROM drive."
|
|
"\nLooking at revision of the SG interface in use...","");
|
|
|
|
- if(ioctl(d->cdda_fd,SG_GET_VERSION_NUM,&version)){
|
|
+ if((version = ioctl(d->cdda_fd,SG_GET_VERSION_NUM,&major)) < 0){
|
|
/* Up, guess not. */
|
|
idmessage(messagedest,messages,
|
|
"\tOOPS! Old 2.0/early 2.1/early 2.2.x (non-ac patch) style "
|
|
"SG.\n\tCdparanoia no longer supports the old interface.\n","");
|
|
return(0);
|
|
}
|
|
- major=version/10000;
|
|
- version-=major*10000;
|
|
- minor=version/100;
|
|
- version-=minor*100;
|
|
+ if (!version)
|
|
+ version = major;
|
|
+
|
|
+ major = (version >> 16) & 0xff;
|
|
+ minor = (version >> 8) & 0xff;
|
|
+ version &= 0xff;
|
|
|
|
sprintf(buffer,"\tSG interface version %d.%d.%d; OK.",
|
|
major,minor,version);
|
|
@@ -431,6 +440,138 @@
|
|
return(major);
|
|
}
|
|
|
|
+#ifdef SG_IO
|
|
+int get_sgio_fd(const char *device, int messagedest, char **messages) {
|
|
+ int fd;
|
|
+
|
|
+ if (!device)
|
|
+ return -errno;
|
|
+ /* we don't really care what type of device it is -- if it can do
|
|
+ * SG_IO, then we'll put it through the normal mmc/atapi/etc tests
|
|
+ * later, but it's good enough for now. */
|
|
+ fd = open(device, O_RDWR|O_EXCL|O_NONBLOCK);
|
|
+ if (fd < 0)
|
|
+ return -errno;
|
|
+ return check_fd_sgio(fd);
|
|
+}
|
|
+
|
|
+/* removing generic_device breaks ABI; instead, just test both devices */
|
|
+static cdrom_drive *sgio_cdda_identify_scsi(const char *generic_device,
|
|
+ const char *ioctl_device, int messagedest,
|
|
+ char **messages){
|
|
+ cdrom_drive *d = NULL;
|
|
+ char *device = NULL;
|
|
+ int fd = -1, g_fd = -1;
|
|
+ char *p;
|
|
+
|
|
+ /* with SG_IO in 2.6, we much prefer /dev/hdc and /dev/scd0, so
|
|
+ * test ioctl_device before testing generic_device */
|
|
+
|
|
+ /* we need to resolve any symlinks for the lookup code to work */
|
|
+ if (ioctl_device)
|
|
+ device = test_resolve_symlink(ioctl_device, messagedest, messages);
|
|
+ /* test again, in case symlink resolution failed */
|
|
+ if (device) {
|
|
+ fd = get_sgio_fd(ioctl_device, messagedest, messages);
|
|
+ if (fd < 0) {
|
|
+ /* ioctl_device didn't work, so we don't need to keep the strdup of its
|
|
+ * real path around */
|
|
+ free(device);
|
|
+ device = NULL;
|
|
+ }
|
|
+ }
|
|
+ if (fd < 0) {
|
|
+ if (!generic_device)
|
|
+ goto cdda_identify_scsi_fail_free;
|
|
+ device = test_resolve_symlink(generic_device, messagedest, messages);
|
|
+ /* test again, in case symlink resolution failed */
|
|
+ if (!device)
|
|
+ goto cdda_identify_scsi_fail_return;
|
|
+ g_fd = get_sgio_fd(device, messagedest, messages);
|
|
+ if (g_fd < 0)
|
|
+ goto cdda_identify_scsi_fail_free;
|
|
+ fd = g_fd;
|
|
+ }
|
|
+
|
|
+ d=calloc(1,sizeof(cdrom_drive));
|
|
+
|
|
+ d->drive_type=SCSI_CDROM_MAJOR;
|
|
+ d->cdda_fd=fd;
|
|
+ d->ioctl_fd=fd;
|
|
+ d->bigendianp=-1; /* We don't know yet... */
|
|
+ d->nsectors=-1;
|
|
+
|
|
+ d->interface=GENERIC_SCSI;
|
|
+
|
|
+ /* alloc our big buffer for scsi commands */
|
|
+ d->sg=calloc(1, sizeof (struct sg_info));
|
|
+ ((struct sg_info *)d->sg)->dxferp_max_buffer_len = CD_FRAMESIZE_RAW;
|
|
+ if (check_fd_sgio(d->cdda_fd))
|
|
+ sgio_init_sg_info(d);
|
|
+ else
|
|
+ sg2_init_sg_info(d);
|
|
+
|
|
+ /* get the lun -- this used to set 0 on failure, maybe still should */
|
|
+ d->lun = -1;
|
|
+
|
|
+ p = scsi_inquiry(d);
|
|
+ if (!p)
|
|
+ goto cdda_identify_scsi_fail_free_device;
|
|
+
|
|
+ /* It would seem some TOSHIBA CDROMs gets things wrong */
|
|
+
|
|
+ if (!strncmp (p + 8, "TOSHIBA", 7) &&
|
|
+ !strncmp (p + 16, "CD-ROM", 6) &&
|
|
+ p[0] == TYPE_DISK) {
|
|
+ p[0] = TYPE_ROM;
|
|
+ p[1] |= 0x80; /* removable */
|
|
+ }
|
|
+
|
|
+ if (!p || (*p != TYPE_ROM && *p != TYPE_WORM)) {
|
|
+ idmessage(messagedest, messages,
|
|
+ "\t\tDrive is neither a CDROM nor a WORM device\n", NULL);
|
|
+ goto cdda_identify_scsi_fail_free_device;
|
|
+ }
|
|
+
|
|
+ memcpy(d->inqbytes, p, 4);
|
|
+ d->cdda_device_name = device;
|
|
+ d->ioctl_device_name = device;
|
|
+
|
|
+ d->drive_model = calloc(1, 36);
|
|
+ strscat(d->drive_model, p+8, 8);
|
|
+ strscat(d->drive_model, p+16, 16);
|
|
+ strscat(d->drive_model, p+32, 4);
|
|
+
|
|
+ idmessage(messagedest, messages, "\nCDROM model sensed sensed: %s", d->drive_model);
|
|
+
|
|
+ return d;
|
|
+
|
|
+cdda_identify_scsi_fail_free_device:
|
|
+ if (d) {
|
|
+ if (d->drive_model)
|
|
+ free(d->drive_model);
|
|
+ if (d->sg) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+
|
|
+ if (sgi->cmdp_buffer_len)
|
|
+ free(sgi->cmdp);
|
|
+ if (sgi->dxferp_buffer_len)
|
|
+ free(sgi->dxferp);
|
|
+ if (sgi->hdr)
|
|
+ free(sgi->hdr);
|
|
+ free(d->sg);
|
|
+ }
|
|
+ free(d);
|
|
+ }
|
|
+ if (fd >= 0)
|
|
+ close(fd);
|
|
+cdda_identify_scsi_fail_free:
|
|
+ if (device)
|
|
+ free(device);
|
|
+cdda_identify_scsi_fail_return:
|
|
+ return NULL;
|
|
+}
|
|
+#endif
|
|
cdrom_drive *cdda_identify_scsi(const char *generic_device,
|
|
const char *ioctl_device, int messagedest,
|
|
char **messages){
|
|
@@ -444,6 +585,12 @@
|
|
int type;
|
|
char *p;
|
|
|
|
+#ifdef SG_IO
|
|
+ d = sgio_cdda_identify_scsi(generic_device, ioctl_device, messagedest, messages);
|
|
+ if (d)
|
|
+ return d;
|
|
+#endif
|
|
+
|
|
if(generic_device)
|
|
idmessage(messagedest,messages,"\tTesting %s for SCSI interface",
|
|
generic_device);
|
|
@@ -580,7 +727,6 @@
|
|
"major number",generic_device);
|
|
goto cdda_identify_scsi_fail;
|
|
}
|
|
-
|
|
|
|
d=calloc(1,sizeof(cdrom_drive));
|
|
|
|
@@ -601,8 +747,9 @@
|
|
}
|
|
|
|
/* malloc our big buffer for scsi commands */
|
|
- d->sg=malloc(MAX_BIG_BUFF_SIZE);
|
|
- d->sg_buffer=d->sg+SG_OFF;
|
|
+ d->sg=calloc(1, sizeof (struct sg_info));
|
|
+ ((struct sg_info *)d->sg)->dxferp_max_buffer_len = CD_FRAMESIZE_RAW;
|
|
+ sg2_init_sg_info(d);
|
|
|
|
{
|
|
/* get the lun */
|
|
@@ -614,6 +761,8 @@
|
|
}
|
|
|
|
p = scsi_inquiry(d);
|
|
+ if (!p)
|
|
+ goto cdda_identify_scsi_fail;
|
|
|
|
/* It would seem some TOSHIBA CDROMs gets things wrong */
|
|
|
|
@@ -632,12 +781,11 @@
|
|
goto cdda_identify_scsi_fail;
|
|
}
|
|
|
|
- d->drive_model=calloc(36,1);
|
|
memcpy(d->inqbytes,p,4);
|
|
d->cdda_device_name=copystring(generic_device);
|
|
d->ioctl_device_name=copystring(ioctl_device);
|
|
|
|
- d->drive_model=calloc(36,1);
|
|
+ d->drive_model=calloc(1, 36);
|
|
strscat(d->drive_model,p+8,8);
|
|
strscat(d->drive_model,p+16,16);
|
|
strscat(d->drive_model,p+32,4);
|
|
@@ -647,6 +795,22 @@
|
|
return(d);
|
|
|
|
cdda_identify_scsi_fail:
|
|
+ if (d) {
|
|
+ if (d->drive_model)
|
|
+ free(d->drive_model);
|
|
+ if (d->sg) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+
|
|
+ if (sgi->cmdp_buffer_len)
|
|
+ free(sgi->cmdp);
|
|
+ if (sgi->dxferp_buffer_len)
|
|
+ free(sgi->dxferp);
|
|
+ if (sgi->hdr)
|
|
+ free(sgi->hdr);
|
|
+ free(d->sg);
|
|
+ }
|
|
+ free(d);
|
|
+ }
|
|
if(generic_device)free((char *)generic_device);
|
|
if(ioctl_device)free((char *)ioctl_device);
|
|
if(i_fd!=-1)close(i_fd);
|
|
--- cdparanoia-III-alpha9.8/interface/scsi_interface.c.sgio 2001-03-23 20:15:46.000000000 -0500
|
|
+++ cdparanoia-III-alpha9.8/interface/scsi_interface.c 2004-03-30 14:19:29.826011776 -0500
|
|
@@ -3,6 +3,7 @@
|
|
* Original interface.c Copyright (C) 1994-1997
|
|
* Eissfeldt heiko@colossus.escape.de
|
|
* Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu
|
|
+ * Copyright 2004 Peter Jones <pjones@redhat.com>
|
|
*
|
|
* Generic SCSI interface specific code.
|
|
*
|
|
@@ -11,6 +12,7 @@
|
|
#include "low_interface.h"
|
|
#include "common_interface.h"
|
|
#include "utils.h"
|
|
+#include "scsi_cmds.h"
|
|
|
|
/* hook */
|
|
static int Dummy (cdrom_drive *d,int s){
|
|
@@ -19,7 +21,290 @@
|
|
|
|
#include "drive_exceptions.h"
|
|
|
|
-static void tweak_SG_buffer(cdrom_drive *d){
|
|
+static void reset_scsi(cdrom_drive *d){
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_io_hdr *hdr = sgi->hdr;
|
|
+ unsigned char key, ASC, ASCQ;
|
|
+ int arg, ret, tries;
|
|
+ char cmd[6];
|
|
+
|
|
+ d->enable_cdda(d,0);
|
|
+
|
|
+ cdmessage(d,"sending SG SCSI reset... ");
|
|
+ if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
|
|
+ cdmessage(d,"FAILED: EBUSY\n");
|
|
+ else
|
|
+ cdmessage(d,"OK\n");
|
|
+
|
|
+ tries = 0;
|
|
+ while(1) {
|
|
+ memcpy(cmd, SCSI_TEST_UNIT_READY_6, 6);
|
|
+ sgi->setup_scsi_cmd(d, cmd, 6, 0, 56);
|
|
+ ret = sgi->handle_scsi_cmd(d);
|
|
+
|
|
+ key = hdr->sbp[2] & 0xf;
|
|
+ ASC = hdr->sbp[12];
|
|
+ ASCQ = hdr->sbp[13];
|
|
+
|
|
+ if(key == 2 & ASC == 4 & ASCQ == 1 & tries < 10) {
|
|
+ tries++;
|
|
+ usleep(10);
|
|
+ continue;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ d->enable_cdda(d,1);
|
|
+}
|
|
+
|
|
+static int check_sbp_error(const char *sbp) {
|
|
+ char key = sbp[2] & 0xf;
|
|
+ char ASC = sbp[12];
|
|
+ char ASCQ = sbp[13];
|
|
+
|
|
+ if (sbp[0]) {
|
|
+ switch (key){
|
|
+ case 0:
|
|
+ if (errno==0)
|
|
+ errno = EIO;
|
|
+ return(TR_UNKNOWN);
|
|
+ case 1:
|
|
+ break;
|
|
+ case 2:
|
|
+ if (errno==0)
|
|
+ errno = EBUSY;
|
|
+ return(TR_BUSY);
|
|
+ case 3:
|
|
+ if ((ASC==0x0C) & (ASCQ==0x09)) {
|
|
+ /* loss of streaming */
|
|
+ if (errno==0)
|
|
+ errno = EIO;
|
|
+ return(TR_STREAMING);
|
|
+ } else {
|
|
+ if (errno==0)
|
|
+ errno = EIO;
|
|
+ return(TR_MEDIUM);
|
|
+ }
|
|
+ case 4:
|
|
+ if (errno==0)
|
|
+ errno = EIO;
|
|
+ return(TR_FAULT);
|
|
+ case 5:
|
|
+ if (errno==0)
|
|
+ errno = EINVAL;
|
|
+ return(TR_ILLEGAL);
|
|
+ default:
|
|
+ if (errno==0)
|
|
+ errno = EIO;
|
|
+ return(TR_UNKNOWN);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef SG_IO
|
|
+int check_fd_sgio(int fd) {
|
|
+ struct sg_io_hdr hdr;
|
|
+
|
|
+ if (fd < 0)
|
|
+ return fd;
|
|
+
|
|
+ memset(&hdr, 0, sizeof (struct sg_io_hdr));
|
|
+ /* First try with interface_id = 'A'; for all but the sg case,
|
|
+ * that'll get us a -EINVAL if it supports SG_IO, and some other
|
|
+ * error for all other cases. */
|
|
+ hdr.interface_id = 'A';
|
|
+ if (ioctl(fd, SG_IO, &hdr)) {
|
|
+ switch (errno) {
|
|
+ /* sr and ata give us EINVAL when SG_IO is supported
|
|
+ * but interface_id is bad. */
|
|
+ case EINVAL:
|
|
+ /* sg gives us ENOSYS when SG_IO is supported but
|
|
+ * interface_id is bad. IMHO, this is wrong and
|
|
+ * needs fixing in the kernel. */
|
|
+ case ENOSYS:
|
|
+ return fd;
|
|
+ /* everything else gives ENOTTY, I think. I'm just
|
|
+ * going to be paranoid and reject everything else. */
|
|
+ default:
|
|
+ return -errno;
|
|
+ }
|
|
+ }
|
|
+ /* if we get here, something is dreadfuly wrong. ioctl(fd,SG_IO,&hdr)
|
|
+ * handled SG_IO, but took hdr.interface_id = 'A' as valid, and an empty
|
|
+ * command as good. Don't trust it. */
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void sgio_tweak_SG_buffer(cdrom_drive *d) {
|
|
+ int table, reserved, cur, err;
|
|
+ char buffer[256];
|
|
+
|
|
+ /* SG_SET_RESERVED_SIZE doesn't actually allocate or reserve anything.
|
|
+ * what it _does_ do is give you an error if you ask for a value
|
|
+ * larger than q->max_sectors (the length of the device's bio request
|
|
+ * queue). So we walk it up from 1 sector until it fails, then get
|
|
+ * the value we set it to last.
|
|
+ */
|
|
+ /* start with 2 frames, round down to our queue's sector size */
|
|
+ cur = 1;
|
|
+ do {
|
|
+ cur <<= 1; reserved = cur * (1<<9);
|
|
+ err = ioctl(d->cdda_fd, SG_SET_RESERVED_SIZE, &reserved);
|
|
+ } while(err >= 0);
|
|
+ ioctl(d->cdda_fd, SG_GET_RESERVED_SIZE, &reserved);
|
|
+
|
|
+ cur = 0;
|
|
+ /* this doesn't currently ever work, but someday somebody might
|
|
+ implement working sg lists with SG_IO devices, so who knows... */
|
|
+ table=1;
|
|
+ if (ioctl(d->cdda_fd, SG_GET_SG_TABLESIZE, &table) < 0)
|
|
+ table=1;
|
|
+
|
|
+ sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t"
|
|
+ "table entry size: %d bytes\n\t"
|
|
+ "maximum theoretical transfer: %d sectors\n",
|
|
+ table, reserved, table*reserved/CD_FRAMESIZE_RAW);
|
|
+ cdmessage(d,buffer);
|
|
+
|
|
+ cur=table*reserved;
|
|
+
|
|
+ ((struct sg_info *)d->sg)->dxferp_max_buffer_len = cur;
|
|
+
|
|
+ /* so since we never go above q->max_sectors, we should never get -EIO.
|
|
+ * we might still get -ENOMEM, but we back off for that later. Monty
|
|
+ * had an old comment: "not too much; new kernels have trouble with DMA
|
|
+ * "allocation, so be more conservative: 32kB max until I test more
|
|
+ * thoroughly". We're not currently honoring that, because we should
|
|
+ * always get -ENOMEM.
|
|
+ */
|
|
+#if 0
|
|
+ cur=(cur>1024*32?1024*32:cur);
|
|
+#endif
|
|
+ d->nsectors=cur/CD_FRAMESIZE_RAW;
|
|
+ d->bigbuff=cur;
|
|
+
|
|
+ sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n",
|
|
+ d->nsectors,d->nsectors*CD_FRAMESIZE_RAW);
|
|
+ cdmessage(d,buffer);
|
|
+}
|
|
+
|
|
+static void sgio_setup_scsi_cmd(cdrom_drive *d,
|
|
+ char *cmdp,
|
|
+ unsigned int cmd_len,
|
|
+ unsigned int in_size,
|
|
+ unsigned int out_size) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_io_hdr *hdr = sgi->hdr;
|
|
+
|
|
+ memset(hdr->cmdp, 0, sgi->cmdp_buffer_len);
|
|
+ memset(hdr->dxferp, sgi->bytefill, sgi->dxferp_buffer_len);
|
|
+ memcpy(hdr->cmdp, cmdp, cmd_len);
|
|
+
|
|
+ hdr->cmd_len = cmd_len;
|
|
+
|
|
+ sgi->in_size = in_size;
|
|
+ sgi->out_size = out_size;
|
|
+}
|
|
+
|
|
+static int sgio_handle_scsi_cmd(cdrom_drive *d) {
|
|
+ int status = 0;
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_io_hdr *hdr = sgi->hdr;
|
|
+
|
|
+ if (sgi->in_size) {
|
|
+ hdr->dxfer_len = sgi->in_size;
|
|
+ hdr->dxfer_direction = SG_DXFER_TO_DEV;
|
|
+
|
|
+ errno = 0;
|
|
+ status = ioctl(d->cdda_fd, SG_IO, hdr);
|
|
+ if (status >= 0)
|
|
+ if (hdr->status)
|
|
+ status = check_sbp_error(hdr->sbp);
|
|
+ if (status < 0)
|
|
+ return TR_EWRITE;
|
|
+ }
|
|
+ if (!sgi->in_size | sgi->out_size) {
|
|
+ hdr->dxfer_len = sgi->out_size;
|
|
+ hdr->dxfer_direction = sgi->out_size ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
|
|
+
|
|
+ errno = 0;
|
|
+ status = ioctl(d->cdda_fd, SG_IO, hdr);
|
|
+ if (status < 0)
|
|
+ return TR_EREAD;
|
|
+ if (status >= 0)
|
|
+ if (hdr->status)
|
|
+ status = check_sbp_error(hdr->sbp);
|
|
+ }
|
|
+ if (status)
|
|
+ return status;
|
|
+
|
|
+ errno = 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void sgio_init_sg_info(cdrom_drive *d) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_io_hdr *hdr;
|
|
+
|
|
+ hdr = calloc(sizeof (struct sg_io_hdr), 1);
|
|
+
|
|
+ sgi->cmdp = hdr->cmdp = calloc(128, 1);
|
|
+ sgi->cmdp_buffer_len = 128;
|
|
+
|
|
+ hdr->sbp = calloc(SG_MAX_SENSE,1);
|
|
+ hdr->mx_sb_len = SG_MAX_SENSE;
|
|
+
|
|
+ sgi->bytefill = '\xff';
|
|
+ sgi->bytecheck = 0;
|
|
+
|
|
+ hdr->timeout = 5000;
|
|
+ hdr->interface_id = 'S';
|
|
+
|
|
+ sgi->hdr = hdr;
|
|
+
|
|
+ sgi->setup_scsi_cmd = sgio_setup_scsi_cmd;
|
|
+ sgi->handle_scsi_cmd = sgio_handle_scsi_cmd;
|
|
+
|
|
+ sgio_tweak_SG_buffer(d);
|
|
+
|
|
+ sgi->dxferp = hdr->dxferp = calloc(sgi->dxferp_max_buffer_len, 1);
|
|
+ sgi->dxferp_buffer_len = sgi->dxferp_max_buffer_len;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void sg2_clear_garbage(cdrom_drive *d){
|
|
+ fd_set fdset;
|
|
+ struct timeval tv;
|
|
+ struct sg_header *sg_hd = (struct sg_header *)((struct sg_info *)d->sg)->hdr;
|
|
+ int flag = 0;
|
|
+
|
|
+ /* clear out any possibly preexisting garbage */
|
|
+ FD_ZERO(&fdset);
|
|
+ FD_SET(d->cdda_fd,&fdset);
|
|
+ tv.tv_sec=0;
|
|
+ tv.tv_usec=0;
|
|
+
|
|
+ /* I like select */
|
|
+ while(select(d->cdda_fd+1,&fdset,NULL,NULL,&tv)==1){
|
|
+
|
|
+ sg_hd->twelve_byte = 0;
|
|
+ sg_hd->result = 0;
|
|
+ sg_hd->reply_len = SG_OFF;
|
|
+ read(d->cdda_fd, sg_hd, 1);
|
|
+
|
|
+ /* reset for select */
|
|
+ FD_ZERO(&fdset);
|
|
+ FD_SET(d->cdda_fd,&fdset);
|
|
+ tv.tv_sec=0;
|
|
+ tv.tv_usec=0;
|
|
+ if(!flag && d->report_all)
|
|
+ cdmessage(d,"Clearing previously returned data from SCSI buffer\n");
|
|
+ flag=1;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void sg2_tweak_SG_buffer(cdrom_drive *d){
|
|
int table,reserved;
|
|
char buffer[256];
|
|
|
|
@@ -58,74 +343,47 @@
|
|
if(ioctl(d->cdda_fd,SG_SET_COMMAND_Q,&reserved)){
|
|
cdmessage(d,"\tCouldn't disable command queue! Continuing anyway...\n");
|
|
}
|
|
-
|
|
}
|
|
|
|
-static void reset_scsi(cdrom_drive *d){
|
|
- int arg;
|
|
- d->enable_cdda(d,0);
|
|
-
|
|
- cdmessage(d,"sending SG SCSI reset... ");
|
|
- if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
|
|
- cdmessage(d,"FAILED: EBUSY\n");
|
|
- else
|
|
- cdmessage(d,"OK\n");
|
|
-
|
|
- d->enable_cdda(d,1);
|
|
-}
|
|
+/* process a complete scsi command. */
|
|
|
|
-static void clear_garbage(cdrom_drive *d){
|
|
- fd_set fdset;
|
|
- struct timeval tv;
|
|
- struct sg_header *sg_hd=(struct sg_header *)d->sg;
|
|
- int flag=0;
|
|
+static void sg2_setup_scsi_cmd(cdrom_drive *d,
|
|
+ char *cmdp,
|
|
+ unsigned int cmd_len,
|
|
+ unsigned int in_size,
|
|
+ unsigned int out_size) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_header *hdr = (struct sg_header *)sgi->hdr;
|
|
|
|
- /* clear out any possibly preexisting garbage */
|
|
- FD_ZERO(&fdset);
|
|
- FD_SET(d->cdda_fd,&fdset);
|
|
- tv.tv_sec=0;
|
|
- tv.tv_usec=0;
|
|
+ sgi->cmdp = (char *)hdr + sizeof (struct sg_header);
|
|
+ memcpy(sgi->cmdp, cmdp, cmd_len);
|
|
|
|
- /* I like select */
|
|
- while(select(d->cdda_fd+1,&fdset,NULL,NULL,&tv)==1){
|
|
-
|
|
- sg_hd->twelve_byte = 0;
|
|
- sg_hd->result = 0;
|
|
- sg_hd->reply_len = SG_OFF;
|
|
- read(d->cdda_fd, sg_hd, 1);
|
|
+ sgi->dxferp = sgi->cmdp + cmd_len;
|
|
+ memset(sgi->dxferp, sgi->bytefill, sgi->dxferp_max_buffer_len - cmd_len);
|
|
|
|
- /* reset for select */
|
|
- FD_ZERO(&fdset);
|
|
- FD_SET(d->cdda_fd,&fdset);
|
|
- tv.tv_sec=0;
|
|
- tv.tv_usec=0;
|
|
- if(!flag && d->report_all)
|
|
- cdmessage(d,"Clearing previously returned data from SCSI buffer\n");
|
|
- flag=1;
|
|
- }
|
|
+ sgi->in_size = in_size;
|
|
+ sgi->out_size = out_size;
|
|
}
|
|
|
|
-/* process a complete scsi command. */
|
|
-static int handle_scsi_cmd(cdrom_drive *d,
|
|
- unsigned int cmd_len,
|
|
- unsigned int in_size,
|
|
- unsigned int out_size,
|
|
-
|
|
- unsigned char bytefill,
|
|
- int bytecheck){
|
|
+static int sg2_handle_scsi_cmd(cdrom_drive *d) {
|
|
int status = 0;
|
|
- struct sg_header *sg_hd=(struct sg_header *)d->sg;
|
|
- long writebytes=SG_OFF+cmd_len+in_size;
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_header *sg_hd = (struct sg_header *)sgi->hdr;
|
|
+
|
|
+ int out_size = sgi->out_size;
|
|
+ int in_size = sgi->in_size;
|
|
+
|
|
+ long writebytes = (int)(sg_hd) + SG_OFF + sgi->cmd_len + sgi->in_size;
|
|
|
|
/* generic scsi device services */
|
|
|
|
/* clear out any possibly preexisting garbage */
|
|
- clear_garbage(d);
|
|
+ sg2_clear_garbage(d);
|
|
|
|
- memset(sg_hd,0,sizeof(sg_hd));
|
|
- sg_hd->twelve_byte = cmd_len == 12;
|
|
+ memset(sg_hd,0, SG_OFF);
|
|
+ sg_hd->twelve_byte = sgi->cmd_len == 12;
|
|
sg_hd->result = 0;
|
|
- sg_hd->reply_len = SG_OFF + out_size;
|
|
+ sg_hd->reply_len = SG_OFF + sgi->out_size;
|
|
|
|
/* The following is one of the scariest hacks I've ever had to use.
|
|
The idea is this: We want to know if a command fails. The
|
|
@@ -135,8 +393,8 @@
|
|
length for a command that doesn't take data) such that we can
|
|
tell if the command failed. Scared yet? */
|
|
|
|
- if(bytecheck && out_size>in_size){
|
|
- memset(d->sg_buffer+cmd_len+in_size,bytefill,out_size-in_size);
|
|
+ if(sgi->bytecheck && out_size>in_size){
|
|
+ /* the memset for this is done in sg2_setup_scsi_cmd() */
|
|
/* the size does not remove cmd_len due to the way the kernel
|
|
driver copies buffers */
|
|
writebytes+=(out_size-in_size);
|
|
@@ -224,40 +482,10 @@
|
|
if(errno==0)errno=EIO;
|
|
return(TR_EREAD);
|
|
}
|
|
-
|
|
- if(sg_hd->sense_buffer[0]){
|
|
- char key=sg_hd->sense_buffer[2]&0xf;
|
|
- char ASC=sg_hd->sense_buffer[12];
|
|
- char ASCQ=sg_hd->sense_buffer[13];
|
|
- switch(key){
|
|
- case 0:
|
|
- if(errno==0)errno=EIO;
|
|
- return(TR_UNKNOWN);
|
|
- case 1:
|
|
- break;
|
|
- case 2:
|
|
- if(errno==0)errno=EBUSY;
|
|
- return(TR_BUSY);
|
|
- case 3:
|
|
- if(ASC==0x0C && ASCQ==0x09){
|
|
- /* loss of streaming */
|
|
- if(errno==0)errno=EIO;
|
|
- return(TR_STREAMING);
|
|
- }else{
|
|
- if(errno==0)errno=EIO;
|
|
- return(TR_MEDIUM);
|
|
- }
|
|
- case 4:
|
|
- if(errno==0)errno=EIO;
|
|
- return(TR_FAULT);
|
|
- case 5:
|
|
- if(errno==0)errno=EINVAL;
|
|
- return(TR_ILLEGAL);
|
|
- default:
|
|
- if(errno==0)errno=EIO;
|
|
- return(TR_UNKNOWN);
|
|
- }
|
|
- }
|
|
+
|
|
+ status = check_sbp_error(sg_hd->sense_buffer);
|
|
+ if (status)
|
|
+ return status;
|
|
|
|
/* still not foolproof; the following doesn't guarantee that we got
|
|
all the data, just that the command was not rejected. */
|
|
@@ -266,10 +494,11 @@
|
|
commands still get through. Perhaps no data comes back even
|
|
though the target reports success? */
|
|
|
|
- if(bytecheck && in_size+cmd_len<out_size){
|
|
+ if(sgi->bytecheck && sgi->in_size+sgi->cmd_len<sgi->out_size){
|
|
long i,flag=0;
|
|
- for(i=in_size;i<out_size;i++)
|
|
- if(d->sg_buffer[i]!=bytefill){
|
|
+ for(i=sgi->in_size; i<sgi->out_size; i++)
|
|
+ /* XXX check this offset */
|
|
+ if((sgi->dxferp[i])!=(sgi->bytefill)){
|
|
flag=1;
|
|
break;
|
|
}
|
|
@@ -284,61 +513,67 @@
|
|
return(0);
|
|
}
|
|
|
|
-/* Group 1 (10b) command */
|
|
+void sg2_init_sg_info(cdrom_drive *d) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_header *hdr;
|
|
|
|
-static int mode_sense_atapi(cdrom_drive *d,int size,int page){
|
|
- memcpy(d->sg_buffer,
|
|
- (char []) {0x5A, /* MODE_SENSE */
|
|
- 0x00, /* reserved */
|
|
- 0x00, /* page */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* MSB (0) */
|
|
- 0, /* sizeof(modesense - SG_OFF) */
|
|
- 0}, /* reserved */
|
|
- 10);
|
|
-
|
|
- d->sg_buffer[1]=d->lun<<5;
|
|
- d->sg_buffer[2]=0x3F&page;
|
|
- d->sg_buffer[8]=size+4;
|
|
+ hdr = calloc(sizeof (struct sg_header)+sgi->dxferp_max_buffer_len, 1);
|
|
|
|
- if (handle_scsi_cmd (d, 10, 0, size+4,'\377',1)) return(1);
|
|
+ sgi->cmdp = (char *)hdr + sizeof (struct sg_header);
|
|
+ sgi->cmdp_buffer_len = 0;
|
|
|
|
- {
|
|
- char *b=d->sg_buffer;
|
|
- if(b[0])return(1); /* Handles only up to 256 bytes */
|
|
- if(b[6])return(1); /* Handles only up to 256 bytes */
|
|
-
|
|
- b[0]=b[1]-3;
|
|
- b[1]=b[2];
|
|
- b[2]=b[3];
|
|
- b[3]=b[7];
|
|
+ sgi->bytefill = '\xff';
|
|
+ sgi->bytecheck = 1;
|
|
|
|
- memmove(b+4,b+8,size);
|
|
- }
|
|
- return(0);
|
|
+ sgi->setup_scsi_cmd = sg2_setup_scsi_cmd;
|
|
+ sgi->handle_scsi_cmd = sg2_handle_scsi_cmd;
|
|
+
|
|
+ sg2_tweak_SG_buffer(d);
|
|
+
|
|
+ // sgi->dxferp = hdr + sizeof (struct sg_header);
|
|
+ sgi->dxferp = NULL;
|
|
+ sgi->dxferp_buffer_len = 0;
|
|
+}
|
|
+
|
|
+static int mode_sense_atapi(cdrom_drive *d, int size, int page) {
|
|
+ char *buffer;
|
|
+
|
|
+ ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SENSE_10(page,size), 10, 0, size);
|
|
+
|
|
+ buffer = ((struct sg_info *)d->sg)->dxferp;
|
|
+#if 0
|
|
+ buffer[1]=d->lun<<5;
|
|
+#endif
|
|
+
|
|
+ if (((struct sg_info *)d->sg)->handle_scsi_cmd(d))
|
|
+ return 1;
|
|
+
|
|
+ if(buffer[0])return(1); /* Handles only up to 256 bytes */
|
|
+ if(buffer[6])return(1); /* Handles only up to 256 bytes */
|
|
+
|
|
+ buffer[0]=buffer[1]-3;
|
|
+ buffer[1]=buffer[2];
|
|
+ buffer[2]=buffer[3];
|
|
+ buffer[3]=buffer[7];
|
|
+
|
|
+ memmove(buffer+4,buffer+8,size);
|
|
+ return 0;
|
|
}
|
|
|
|
/* group 0 (6b) command */
|
|
|
|
static int mode_sense_scsi(cdrom_drive *d,int size,int page){
|
|
- memcpy(d->sg_buffer,
|
|
- (char []) {0x1A, /* MODE_SENSE */
|
|
- 0x00, /* return block descriptor/lun */
|
|
- 0x00, /* page */
|
|
- 0, /* reserved */
|
|
- 0, /* sizeof(modesense - SG_OFF) */
|
|
- 0}, /* control */
|
|
- 6);
|
|
+ char *buffer;
|
|
+ ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SENSE_6(page, size), 6, 0, size);
|
|
|
|
- d->sg_buffer[1]=d->lun<<5;
|
|
- d->sg_buffer[2]=(0x3F&page);
|
|
- d->sg_buffer[4]=size;
|
|
-
|
|
- if (handle_scsi_cmd (d, 6, 0, size, '\377',1)) return(1);
|
|
- return(0);
|
|
+ buffer = ((struct sg_info *)d->sg)->dxferp;
|
|
+#if 0
|
|
+ buffer[1]=d->lun<<5;
|
|
+#endif
|
|
+
|
|
+ if (((struct sg_info *)d->sg)->handle_scsi_cmd(d))
|
|
+ return 1;
|
|
+ return 0;
|
|
}
|
|
|
|
static int mode_sense(cdrom_drive *d,int size,int page){
|
|
@@ -347,80 +582,77 @@
|
|
return(mode_sense_scsi(d,size,page));
|
|
}
|
|
|
|
-static int mode_select(cdrom_drive *d,int density,int secsize){
|
|
- /* short circut the way Heiko does it; less flexible, but shorter */
|
|
- if(d->is_atapi){
|
|
- unsigned char *mode = d->sg_buffer + 18;
|
|
+static int atapi_mode_select(cdrom_drive *d, int density, int secsize) {
|
|
+ unsigned char *mode;
|
|
|
|
- memcpy(d->sg_buffer,
|
|
- (char []) { 0x55, /* MODE_SELECT */
|
|
- 0x10, /* no save page */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 12, /* sizeof(mode) */
|
|
- 0, /* reserved */
|
|
-
|
|
- /* mode parameter header */
|
|
- 0, 0, 0, 0, 0, 0, 0,
|
|
- 8, /* Block Descriptor Length */
|
|
-
|
|
- /* descriptor block */
|
|
- 0, /* Density Code */
|
|
- 0, 0, 0, /* # of Blocks */
|
|
- 0, /* reserved */
|
|
- 0, 0, 0},/* Blocklen */
|
|
- 26);
|
|
-
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
-
|
|
- /* prepare to read cds in the previous mode */
|
|
- mode [0] = density;
|
|
- mode [6] = secsize >> 8; /* block length "msb" */
|
|
- mode [7] = secsize & 0xFF; /* block length lsb */
|
|
+ ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SELECT_10, 10, 16, 0);
|
|
+ memcpy(((struct sg_info *)d->sg)->dxferp,(char []) {
|
|
+ /* mode parameter header */
|
|
+ 0, 0, 0, 0, 0, 0, 0,
|
|
+ 8, /* Block Descriptor Length */
|
|
+ /* descriptor block */
|
|
+ 0, /* Density Code */
|
|
+ 0, 0, 0, /* # of Blocks */
|
|
+ 0, /* reserved */
|
|
+ 0, 0, 0},/* Blocklen */
|
|
+ 16);
|
|
+
|
|
+ mode = ((struct sg_info *)d->sg)->dxferp;
|
|
+#if 0
|
|
+ mode[1] |= d->lun << 5;
|
|
+#endif
|
|
+ /* prepare to read cds in the previous mode */
|
|
+ mode[8] = density;
|
|
+ mode[14] = secsize >> 8; /* block length "msb" */
|
|
+ mode[15] = secsize & 0xFF; /* block length lsb */
|
|
+
|
|
+ /* do the scsi cmd */
|
|
+ return ((struct sg_info *)d->sg)->handle_scsi_cmd(d);
|
|
+}
|
|
+
|
|
+static int scsi_mode_select(cdrom_drive *d, int density, int secsize) {
|
|
+ unsigned char *mode;
|
|
+
|
|
+ ((struct sg_info *)d->sg)->setup_scsi_cmd(d, SCSI_MODE_SELECT_6, 6, 12, 0);
|
|
+ memcpy(((struct sg_info *)d->sg)->dxferp,(char []) {
|
|
+ /* mode section */
|
|
+ 0,
|
|
+ 0, 0,
|
|
+ 8, /* Block Descriptor Length */
|
|
+ 0, /* Density Code */
|
|
+ 0, 0, 0, /* # of Blocks */
|
|
+ 0, /* reserved */
|
|
+ 0, 0, 0},/* Blocklen */
|
|
+ 12);
|
|
+
|
|
+ /* prepare to read cds in the previous mode */
|
|
+ mode = ((struct sg_info *)d->sg)->dxferp;
|
|
+ mode [4] = density;
|
|
+ mode [10] = secsize >> 8; /* block length "msb" */
|
|
+ mode [11] = secsize & 0xFF; /* block length lsb */
|
|
|
|
/* do the scsi cmd */
|
|
- return(handle_scsi_cmd (d,10, 16, 0,0,0));
|
|
-
|
|
- }else{
|
|
- unsigned char *mode = d->sg_buffer + 10;
|
|
-
|
|
- memcpy(d->sg_buffer,
|
|
- (char []) { 0x15, /* MODE_SELECT */
|
|
- 0x10, /* no save page */
|
|
- 0, /* reserved */
|
|
- 0, /* reserved */
|
|
- 12, /* sizeof(mode) */
|
|
- 0, /* reserved */
|
|
- /* mode section */
|
|
- 0,
|
|
- 0, 0,
|
|
- 8, /* Block Descriptor Length */
|
|
- 0, /* Density Code */
|
|
- 0, 0, 0, /* # of Blocks */
|
|
- 0, /* reserved */
|
|
- 0, 0, 0},/* Blocklen */
|
|
- 18);
|
|
-
|
|
- /* prepare to read cds in the previous mode */
|
|
- mode [0] = density;
|
|
- mode [6] = secsize >> 8; /* block length "msb" */
|
|
- mode [7] = secsize & 0xFF; /* block length lsb */
|
|
+ return ((struct sg_info *)d->sg)->handle_scsi_cmd(d);
|
|
+}
|
|
|
|
- /* do the scsi cmd */
|
|
- return(handle_scsi_cmd (d,6, 12, 0,0,0));
|
|
- }
|
|
+static int mode_select(cdrom_drive *d, int density, int secsize) {
|
|
+ /* short circut the way Heiko does it; less flexible, but shorter */
|
|
+ if (d->is_atapi)
|
|
+ return atapi_mode_select(d, density, secsize);
|
|
+ return scsi_mode_select(d, density, secsize);
|
|
}
|
|
|
|
/* get current sector size from SCSI cdrom drive */
|
|
static unsigned int get_orig_sectorsize(cdrom_drive *d){
|
|
- if(mode_sense(d,12,0x01))return(-1);
|
|
+ if (mode_sense(d,12,0x01))
|
|
+ return -1;
|
|
+
|
|
+ d->orgdens = ((struct sg_info *)d->sg)->dxferp[4];
|
|
+
|
|
+ d->orgsize = (int)(((struct sg_info *)d->sg)->dxferp[10]<<8);
|
|
+ d->orgsize += (int)((struct sg_info *)d->sg)->dxferp[11];
|
|
|
|
- d->orgdens = d->sg_buffer[4];
|
|
- return(d->orgsize = ((int)(d->sg_buffer[10])<<8)+d->sg_buffer[11]);
|
|
+ return d->orgsize;
|
|
}
|
|
|
|
/* switch CDROM scsi drives to given sector size */
|
|
@@ -463,23 +695,23 @@
|
|
fails on at least one Kodak drive. */
|
|
|
|
static int scsi_read_toc (cdrom_drive *d){
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
int i,first,last;
|
|
unsigned tracks;
|
|
-
|
|
- /* READTOC, MSF format flag, res, res, res, res, Start track, len msb,
|
|
- len lsb, flags */
|
|
+ scsi_TOC *toc;
|
|
|
|
/* read the header first */
|
|
- memcpy(d->sg_buffer, (char []){ 0x43, 0, 0, 0, 0, 0, 1, 0, 12, 0}, 10);
|
|
- d->sg_buffer[1]=d->lun<<5;
|
|
-
|
|
- if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
|
|
+ sgi->setup_scsi_cmd(d, SCSI_READ_TOC(1), 10, 0, 12);
|
|
+#if 0
|
|
+ sgi->dxferp[1] = d->lun << 5;
|
|
+#endif
|
|
+ if (sgi->handle_scsi_cmd(d)) {
|
|
cderror(d,"004: Unable to read table of contents header\n");
|
|
return(-4);
|
|
}
|
|
|
|
- first=d->sg_buffer[2];
|
|
- last=d->sg_buffer[3];
|
|
+ first = sgi->dxferp[2];
|
|
+ last = sgi->dxferp[3];
|
|
tracks=last-first+1;
|
|
|
|
if (last > MAXTRK || first > MAXTRK || last<0 || first<0) {
|
|
@@ -488,335 +720,208 @@
|
|
}
|
|
|
|
for (i = first; i <= last; i++){
|
|
- memcpy(d->sg_buffer, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
|
|
- d->sg_buffer[1]=d->lun<<5;
|
|
- d->sg_buffer[6]=i;
|
|
+ sgi->setup_scsi_cmd(d, SCSI_READ_TOC(i), 10, 0, 12);
|
|
+#if 0
|
|
+ sgi->dxferp[1] = d->lun << 5;
|
|
+#endif
|
|
|
|
- if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
|
|
+ if (sgi->handle_scsi_cmd(d)) {
|
|
cderror(d,"005: Unable to read table of contents entry\n");
|
|
return(-5);
|
|
}
|
|
- {
|
|
- scsi_TOC *toc=(scsi_TOC *)(d->sg_buffer+4);
|
|
-
|
|
- d->disc_toc[i-first].bFlags=toc->bFlags;
|
|
- d->disc_toc[i-first].bTrack=i;
|
|
- d->disc_toc[i-first].dwStartSector= d->adjust_ssize *
|
|
- (((int)(toc->start_MSB)<<24) |
|
|
- (toc->start_1<<16)|
|
|
- (toc->start_2<<8)|
|
|
- (toc->start_LSB));
|
|
- }
|
|
- }
|
|
+ toc = (scsi_TOC *)(sgi->dxferp+4);
|
|
+ d->disc_toc[i-first].bFlags = toc->bFlags;
|
|
+ d->disc_toc[i-first].bTrack = i;
|
|
+ d->disc_toc[i-first].dwStartSector =
|
|
+ d->adjust_ssize * (
|
|
+ ((int)(toc->start_MSB)<<24) | (toc->start_1 << 16) |
|
|
+ (toc->start_2 << 8) | (toc->start_LSB)
|
|
+ );
|
|
+ }
|
|
+
|
|
+ sgi->setup_scsi_cmd(d, SCSI_READ_TOC(0xAA), 10, 0, 12);
|
|
+#if 0
|
|
+ sgi->dxferp[1] = d->lun << 5;
|
|
+#endif
|
|
|
|
- memcpy(d->sg_buffer, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
|
|
- d->sg_buffer[1]=d->lun<<5;
|
|
- d->sg_buffer[6]=0xAA;
|
|
-
|
|
- if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){
|
|
+ if (sgi->handle_scsi_cmd(d)) {
|
|
cderror(d,"002: Unable to read table of contents lead-out\n");
|
|
return(-2);
|
|
}
|
|
- {
|
|
- scsi_TOC *toc=(scsi_TOC *)(d->sg_buffer+4);
|
|
-
|
|
- d->disc_toc[i-first].bFlags=toc->bFlags;
|
|
- d->disc_toc[i-first].bTrack=0xAA;
|
|
- d->disc_toc[i-first].dwStartSector= d->adjust_ssize *
|
|
- (((int)(toc->start_MSB)<<24) |
|
|
- (toc->start_1<<16)|
|
|
- (toc->start_2<<8)|
|
|
- (toc->start_LSB));
|
|
- }
|
|
+
|
|
+ toc = (scsi_TOC *)(sgi->dxferp+4);
|
|
+ d->disc_toc[i-first].bFlags = toc->bFlags;
|
|
+ d->disc_toc[i-first].bTrack = 0xAA;
|
|
+ d->disc_toc[i-first].dwStartSector =
|
|
+ d->adjust_ssize * (
|
|
+ ((int)(toc->start_MSB)<<24) | (toc->start_1 << 16) |
|
|
+ (toc->start_2 << 8) | (toc->start_LSB)
|
|
+ );
|
|
|
|
d->cd_extra = FixupTOC(d,tracks+1); /* include lead-out */
|
|
- return(tracks);
|
|
+ return tracks;
|
|
}
|
|
|
|
/* a contribution from Boris for IMS cdd 522 */
|
|
/* check this for ACER/Creative/Foo 525,620E,622E, etc? */
|
|
static int scsi_read_toc2 (cdrom_drive *d){
|
|
- u_int32_t foo,bar;
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ u_int32_t msb,lsb;
|
|
|
|
int i;
|
|
unsigned tracks;
|
|
|
|
- memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
|
|
- d->sg_buffer[5]=1;
|
|
- d->sg_buffer[8]=255;
|
|
-
|
|
- if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
|
|
+ sgi->setup_scsi_cmd(d, CDD522_READ_TOC(1), 10, 0, 256);
|
|
+ if (sgi->handle_scsi_cmd(d)) {
|
|
cderror(d,"004: Unable to read table of contents header\n");
|
|
return(-4);
|
|
}
|
|
|
|
/* copy to our structure and convert start sector */
|
|
- tracks = d->sg_buffer[1];
|
|
+ tracks = sgi->dxferp[1];
|
|
if (tracks > MAXTRK) {
|
|
cderror(d,"003: CDROM reporting illegal number of tracks\n");
|
|
return(-3);
|
|
}
|
|
|
|
for (i = 0; i < tracks; i++){
|
|
- memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
|
|
- d->sg_buffer[5]=i+1;
|
|
- d->sg_buffer[8]=255;
|
|
+ sgi->setup_scsi_cmd(d, CDD522_READ_TOC(i+1), 10, 0, 256);
|
|
|
|
- if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){
|
|
+ if (sgi->handle_scsi_cmd(d)) {
|
|
cderror(d,"005: Unable to read table of contents entry\n");
|
|
return(-5);
|
|
}
|
|
|
|
- d->disc_toc[i].bFlags = d->sg_buffer[10];
|
|
+ d->disc_toc[i].bFlags = sgi->dxferp[10];
|
|
d->disc_toc[i].bTrack = i + 1;
|
|
|
|
- d->disc_toc[i].dwStartSector= d->adjust_ssize *
|
|
- (((signed char)(d->sg_buffer[2])<<24) |
|
|
- (d->sg_buffer[3]<<16)|
|
|
- (d->sg_buffer[4]<<8)|
|
|
- (d->sg_buffer[5]));
|
|
+ d->disc_toc[i].dwStartSector = d->adjust_ssize * (
|
|
+ ((signed char)(sgi->dxferp[2])<<24) |
|
|
+ (sgi->dxferp[3]<<16) |
|
|
+ (sgi->dxferp[4]<<8) |
|
|
+ (sgi->dxferp[5])
|
|
+ );
|
|
}
|
|
|
|
d->disc_toc[i].bFlags = 0;
|
|
d->disc_toc[i].bTrack = i + 1;
|
|
- memcpy (&foo, d->sg_buffer+2, 4);
|
|
- memcpy (&bar, d->sg_buffer+6, 4);
|
|
- d->disc_toc[i].dwStartSector = d->adjust_ssize * (be32_to_cpu(foo) +
|
|
- be32_to_cpu(bar));
|
|
-
|
|
- d->disc_toc[i].dwStartSector= d->adjust_ssize *
|
|
- ((((signed char)(d->sg_buffer[2])<<24) |
|
|
- (d->sg_buffer[3]<<16)|
|
|
- (d->sg_buffer[4]<<8)|
|
|
- (d->sg_buffer[5]))+
|
|
-
|
|
- ((((signed char)(d->sg_buffer[6])<<24) |
|
|
- (d->sg_buffer[7]<<16)|
|
|
- (d->sg_buffer[8]<<8)|
|
|
- (d->sg_buffer[9]))));
|
|
-
|
|
+ memcpy (&msb, sgi->dxferp+2, 4);
|
|
+ memcpy (&lsb, sgi->dxferp+6, 4);
|
|
+ d->disc_toc[i].dwStartSector = d->adjust_ssize *
|
|
+ (be32_to_cpu(msb) + be32_to_cpu(lsb));
|
|
+
|
|
+ d->disc_toc[i].dwStartSector= d->adjust_ssize * (
|
|
+ ((((signed char)(sgi->dxferp[2])<<24) |
|
|
+ (sgi->dxferp[3]<<16) |
|
|
+ (sgi->dxferp[4]<<8) |
|
|
+ (sgi->dxferp[5])
|
|
+ ) + (
|
|
+ ((signed char)(sgi->dxferp[6])<<24) |
|
|
+ (sgi->dxferp[7]<<16) |
|
|
+ (sgi->dxferp[8]<<8) |
|
|
+ (sgi->dxferp[9])))
|
|
+ );
|
|
|
|
d->cd_extra = FixupTOC(d,tracks+1);
|
|
- return(tracks);
|
|
+ return tracks;
|
|
}
|
|
|
|
/* These do one 'extra' copy in the name of clean code */
|
|
|
|
-static int i_read_28 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
+static int generic_scsi_read(cdrom_drive *d, void *p, long begin, long sectors,
|
|
+ char *read_cmd, int len, int in_size, int out_size) {
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
int ret;
|
|
- memcpy(d->sg_buffer,(char []){0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
|
|
-
|
|
- if(d->fua)
|
|
- d->sg_buffer[1]=0x08;
|
|
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
+ sgi->setup_scsi_cmd(d, read_cmd, len, in_size, out_size);
|
|
+#if 0
|
|
+ sgi->dxferp[1] = d->lun << 5;
|
|
+#endif
|
|
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[8] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+ ret = sgi->handle_scsi_cmd(d);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ if (p)
|
|
+ memcpy(p, sgi->dxferp, sectors * CD_FRAMESIZE_RAW);
|
|
+ return 0;
|
|
}
|
|
|
|
-static int i_read_A8 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
|
|
-
|
|
- if(d->fua)
|
|
- d->sg_buffer[1]=0x08;
|
|
-
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
-
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[9] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_28(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ SCSI_READ_10(d->fua, begin, sectors), 10, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_D4_10 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
|
|
-
|
|
- if(d->fua)
|
|
- d->sg_buffer[1]=0x08;
|
|
-
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[8] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_A8(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ SCSI_READ_12(d->fua, begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_D4_12 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
|
|
-
|
|
- if(d->fua)
|
|
- d->sg_buffer[1]=0x08;
|
|
-
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[9] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_D4_10(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ D4_READ_10(begin, sectors), 10, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_D5 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0},10);
|
|
-
|
|
- if(d->fua)
|
|
- d->sg_buffer[1]=0x08;
|
|
-
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[8] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_D4_12(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ D4_READ_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_D8 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12);
|
|
-
|
|
- if(d->fua)
|
|
- d->sg_buffer[1]=0x08;
|
|
-
|
|
- d->sg_buffer[1]|=d->lun<<5;
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[9] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_D5(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ D5_READ_10(begin, sectors), 10, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_mmc (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- /* if(begin<=12007 && begin+sectors>12000){
|
|
- errno=EIO;
|
|
- return(TR_ILLEGAL);
|
|
- }*/
|
|
-
|
|
- memcpy(d->sg_buffer,(char []){0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
|
|
-
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[8] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_D8(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ D8_READ_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
|
|
-
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[8] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_mmc(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ READ_CD_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-static int i_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xbe, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
|
|
+static int i_read_mmc2(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ char cmd[12];
|
|
|
|
- d->sg_buffer[3] = (begin >> 16) & 0xFF;
|
|
- d->sg_buffer[4] = (begin >> 8) & 0xFF;
|
|
- d->sg_buffer[5] = begin & 0xFF;
|
|
- d->sg_buffer[8] = sectors;
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+ memcpy(cmd, READ_CD_12(begin, sectors), 12);
|
|
+ cmd[9] = 0xf8;
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
-/* straight from the MMC3 spec */
|
|
-static inline void LBA_to_MSF(long lba,
|
|
- unsigned char *M,
|
|
- unsigned char *S,
|
|
- unsigned char *F){
|
|
- if(lba>=-150){
|
|
- *M=(lba+150)/(60*75);
|
|
- lba-=(*M)*60*75;
|
|
- *S=(lba+150)/75;
|
|
- lba-=(*S)*75;
|
|
- *F=(lba+150);
|
|
- }else{
|
|
- *M=(lba+450150)/(60*75);
|
|
- lba-=(*M)*60*75;
|
|
- *S=(lba+450150)/75;
|
|
- lba-=(*S)*75;
|
|
- *F=(lba+450150);
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
-static int i_read_msf (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12);
|
|
+static int i_read_mmc3(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ char cmd[12];
|
|
|
|
- LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
|
|
- LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
|
|
+ memcpy(cmd, READ_CD_12(begin, sectors), 12);
|
|
+ cmd[1] = 4;
|
|
+ cmd[9] = 0xf8;
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
+}
|
|
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+static int i_read_msf(cdrom_drive *d, void *p, long begin, long sectors){
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ READ_CD_MSF_12(begin, sectors), 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
static int i_read_msf2 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
|
|
+ char cmd[12];
|
|
|
|
- LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
|
|
- LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
|
|
-
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+ memcpy(cmd, READ_CD_MSF_12(begin, sectors), 12);
|
|
+ cmd[9] = 0xf8;
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
static int i_read_msf3 (cdrom_drive *d, void *p, long begin, long sectors){
|
|
- int ret;
|
|
- memcpy(d->sg_buffer,(char []){0xb9, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12);
|
|
+ char cmd[12];
|
|
|
|
- LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5);
|
|
- LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8);
|
|
-
|
|
- if((ret=handle_scsi_cmd(d,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1)))
|
|
- return(ret);
|
|
- if(p)memcpy(p,d->sg_buffer,sectors*CD_FRAMESIZE_RAW);
|
|
- return(0);
|
|
+ memcpy(cmd, READ_CD_MSF_12(begin, sectors), 12);
|
|
+ cmd[1] = 4;
|
|
+ cmd[9] = 0xf8;
|
|
+ return generic_scsi_read(d, p, begin, sectors,
|
|
+ cmd, 12, 0, sectors * CD_FRAMESIZE_RAW);
|
|
}
|
|
|
|
static long scsi_read_map (cdrom_drive *d, void *p, long begin, long sectors,
|
|
@@ -824,6 +929,10 @@
|
|
int retry_count,err;
|
|
char *buffer=(char *)p;
|
|
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
+ struct sg_io_hdr *hdr = sgi->hdr;
|
|
+ unsigned char key, ASC, ASCQ;
|
|
+
|
|
/* read d->nsectors at a time, max. */
|
|
sectors=(sectors>d->nsectors?d->nsectors:sectors);
|
|
sectors=(sectors<1?1:sectors);
|
|
@@ -832,17 +941,32 @@
|
|
|
|
while(1) {
|
|
if((err=map(d,(p?buffer:NULL),begin,sectors))){
|
|
+ /* Dunno if we even need this now that scsi_reset does it,
|
|
+ * but try to take "device is becoming ready" into account */
|
|
+ key = hdr->sbp[2] & 0xf;
|
|
+ ASC = hdr->sbp[12];
|
|
+ ASCQ = hdr->sbp[13];
|
|
+
|
|
+ if(key == 2 & ASC == 4 & ASCQ == 1) {
|
|
+ if(retry_count > MAX_RETRIES-1) {
|
|
+ char b[256];
|
|
+ sprintf(b,"010: Unable to access sector %ld\n",
|
|
+ begin);
|
|
+ cderror(d,b);
|
|
+ return(-10);
|
|
+ } else {
|
|
+ retry_count++;
|
|
+ usleep(100);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
if(d->report_all){
|
|
- struct sg_header *sg_hd=(struct sg_header *)d->sg;
|
|
char b[256];
|
|
-
|
|
sprintf(b,"scsi_read error: sector=%ld length=%ld retry=%d\n",
|
|
begin,sectors,retry_count);
|
|
cdmessage(d,b);
|
|
sprintf(b," Sense key: %x ASC: %x ASCQ: %x\n",
|
|
- (int)(sg_hd->sense_buffer[2]&0xf),
|
|
- (int)(sg_hd->sense_buffer[12]),
|
|
- (int)(sg_hd->sense_buffer[13]));
|
|
+ key, ASC, ASCQ);
|
|
cdmessage(d,b);
|
|
sprintf(b," Transport error: %s\n",strerror_tr[err]);
|
|
cdmessage(d,b);
|
|
@@ -852,9 +976,7 @@
|
|
fprintf(stderr,"scsi_read error: sector=%ld length=%ld retry=%d\n",
|
|
begin,sectors,retry_count);
|
|
fprintf(stderr," Sense key: %x ASC: %x ASCQ: %x\n",
|
|
- (int)(sg_hd->sense_buffer[2]&0xf),
|
|
- (int)(sg_hd->sense_buffer[12]),
|
|
- (int)(sg_hd->sense_buffer[13]));
|
|
+ key, ASC, ASCQ);
|
|
fprintf(stderr," Transport error: %s\n",strerror_tr[err]);
|
|
fprintf(stderr," System error: %s\n",strerror(errno));
|
|
}
|
|
@@ -1014,7 +1136,7 @@
|
|
static int count_2352_bytes(cdrom_drive *d){
|
|
long i;
|
|
for(i=2351;i>=0;i--)
|
|
- if(d->sg_buffer[i]!=(unsigned char)'\177')
|
|
+ if(((struct sg_info *)d->sg)->dxferp[i]!=(unsigned char)'\177')
|
|
return(((i+3)>>2)<<2);
|
|
|
|
return(0);
|
|
@@ -1023,7 +1145,7 @@
|
|
static int verify_nonzero(cdrom_drive *d){
|
|
long i,flag=0;
|
|
for(i=0;i<2352;i++)
|
|
- if(d->sg_buffer[i]!=0){
|
|
+ if(((struct sg_info *)d->sg)->dxferp[i]!=0){
|
|
flag=1;
|
|
break;
|
|
}
|
|
@@ -1307,7 +1429,17 @@
|
|
return;
|
|
}
|
|
|
|
-static int check_atapi(cdrom_drive *d){
|
|
+static int check_sgio(cdrom_drive *d) {
|
|
+ int fd = d->cdda_fd;
|
|
+
|
|
+#ifdef SG_IO
|
|
+ if (fd == check_fd_sgio(fd))
|
|
+ return 1;
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int check_atapi(cdrom_drive *d, int using_sgio){
|
|
int atapiret=-1;
|
|
int fd = d->cdda_fd; /* this is the correct fd (not ioctl_fd), as the
|
|
generic device is the device we need to check */
|
|
@@ -1321,7 +1453,7 @@
|
|
if(atapiret==1){
|
|
cdmessage(d,"\tDrive is ATAPI (using SCSI host adaptor emulation)\n");
|
|
/* Disable kernel SCSI command translation layer for access through sg */
|
|
- if (ioctl(fd,SG_SET_TRANSFORM,0))
|
|
+ if (!using_sgio && ioctl(fd,SG_SET_TRANSFORM,0))
|
|
cderror(d,"\tCouldn't disable kernel command translation layer\n");
|
|
d->is_atapi=1;
|
|
}else{
|
|
@@ -1340,7 +1472,7 @@
|
|
d->is_mmc=0;
|
|
if(mode_sense(d,22,0x2A)==0){
|
|
|
|
- b=d->sg_buffer;
|
|
+ b=((struct sg_info *)d->sg)->dxferp;
|
|
b+=b[3]+4;
|
|
|
|
if((b[0]&0x3F)==0x2A){
|
|
@@ -1380,21 +1512,27 @@
|
|
}
|
|
|
|
/* request vendor brand and model */
|
|
-unsigned char *scsi_inquiry(cdrom_drive *d){
|
|
- memcpy(d->sg_buffer,(char[]){ 0x12,0,0,0,56,0},6);
|
|
+unsigned char *scsi_inquiry(cdrom_drive *d) {
|
|
+ static char ret[56];
|
|
+ struct sg_info *sgi = (struct sg_info *)d->sg;
|
|
|
|
- if(handle_scsi_cmd(d,6, 0, 56,'\377',1)) {
|
|
+ if (sgi->hdr == NULL)
|
|
+ scsi_init_drive(d);
|
|
+
|
|
+ sgi->setup_scsi_cmd(d, SCSI_INQUIRY_6(56), 6, 0, 56);
|
|
+ if (sgi->handle_scsi_cmd(d)) {
|
|
cderror(d,"008: Unable to identify CDROM model\n");
|
|
- return(NULL);
|
|
+ return NULL;
|
|
}
|
|
- return (d->sg_buffer);
|
|
+ memcpy(ret, ((struct sg_info *)d->sg)->dxferp, 56);
|
|
+ return ret;
|
|
}
|
|
|
|
-
|
|
int scsi_init_drive(cdrom_drive *d){
|
|
- int ret;
|
|
+ int ret, is_sgio;
|
|
|
|
- check_atapi(d);
|
|
+ is_sgio = check_sgio(d);
|
|
+ check_atapi(d, is_sgio);
|
|
check_mmc(d);
|
|
|
|
/* generic Sony type defaults; specialize from here */
|
|
@@ -1451,15 +1589,16 @@
|
|
if(d->tracks<1)
|
|
return(d->tracks);
|
|
|
|
- tweak_SG_buffer(d);
|
|
d->opened=1;
|
|
|
|
if((ret=verify_read_command(d)))return(ret);
|
|
check_fua_bit(d);
|
|
|
|
d->error_retry=1;
|
|
- d->sg=realloc(d->sg,d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128);
|
|
- d->sg_buffer=d->sg+SG_OFF;
|
|
+#if 0
|
|
+ ((struct sg_info *)d->sg)=realloc(((struct sg_info *)d->sg),d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128);
|
|
+ ((struct sg_info *)d->sg)_buffer=((struct sg_info *)d->sg)+SG_OFF;
|
|
+#endif
|
|
d->report_all=1;
|
|
return(0);
|
|
}
|
|
--- cdparanoia-III-alpha9.8/interface/scsi_cmds.h.sgio 2004-03-30 12:46:03.306332320 -0500
|
|
+++ cdparanoia-III-alpha9.8/interface/scsi_cmds.h 2004-03-30 14:09:53.760587032 -0500
|
|
@@ -0,0 +1,197 @@
|
|
+/******************************************************************
|
|
+ * CopyPolicy: GNU General Public License version 2
|
|
+ * Copyright 2004 Peter Jones <pjones@redhat.com>
|
|
+ *
|
|
+ * macros to generate scsi commands.
|
|
+ *
|
|
+ ******************************************************************/
|
|
+
|
|
+#ifndef _SCSI_CMDS_H
|
|
+#define _SCSI_CMDS_H 1
|
|
+#include <scsi/scsi.h>
|
|
+
|
|
+/* from the MMC3 spec, rewritten as seperate macros */
|
|
+#define LBA_to_M(lba) (lba>=-150?((lba+150)/(60*75)):((lba+450150)/(60*75)))
|
|
+#define LBA_to_S(lba) (lba>=-150?((lba+150)/75):((lba+450150)/75))
|
|
+#define LBA_to_F(lba) (lba>=-150?(lba+150):(lba+450150))
|
|
+
|
|
+/* Group 1 (10b) command */
|
|
+#define SCSI_TWELVE_BYTE(a,b,c,d,e,f,g,h,i,j,k,l) ((char []) {a,b,c,d,e,f,g,h,i,j,k,l})
|
|
+#define SCSI_READ_12(fua, a, l) SCSI_TWELVE_BYTE( \
|
|
+ READ_12, /* READ_10 */ \
|
|
+ (fua & 1) << 3, /* force unit access */ \
|
|
+ (a >> 24) & 0xff, /* lba byte 3 */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ 0, /* reserved */ \
|
|
+ (l >> 24) & 0xff, /* len byte 3 */ \
|
|
+ (l >> 16) & 0xff, /* len byte 2 */ \
|
|
+ (l >> 8) & 0xff, /* len byte 1 */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 0 /* control */ \
|
|
+)
|
|
+#define D4_READ_12(a, l) SCSI_TWELVE_BYTE( \
|
|
+ 0xD4, /* 0xD4 */ \
|
|
+ 0, /* lun */ \
|
|
+ 0, /* ? */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* ? */ \
|
|
+ 0, /* ? */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 0, 0 /* ? */ \
|
|
+)
|
|
+#define D8_READ_12(a, l) SCSI_TWELVE_BYTE( \
|
|
+ 0xD8, /* 0xD4 */ \
|
|
+ 0, /* lun */ \
|
|
+ 0, /* ? */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* ? */ \
|
|
+ 0, /* ? */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 0, 0 /* ? */ \
|
|
+)
|
|
+#define READ_CD_12(a, l) SCSI_TWELVE_BYTE( \
|
|
+ 0xBE, /* 0xD4 */ \
|
|
+ 0, /* ? */ \
|
|
+ (a >> 24) & 0xff, /* lba byte 3 */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ (l >> 16) & 0xff, /* len byte 2 */ \
|
|
+ (l >> 8) & 0xff, /* len byte 1 */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 10, /* ecc */ \
|
|
+ 0, 0 /* ? */ \
|
|
+)
|
|
+#define READ_CD_MSF_12(a, l) SCSI_TWELVE_BYTE( \
|
|
+ 0xB9, /* 0xD4 */ \
|
|
+ 0, /* ? */ \
|
|
+ 0, /* ? */ \
|
|
+ LBA_to_M((a)), /* start M */ \
|
|
+ LBA_to_S((a)), /* start S */ \
|
|
+ LBA_to_F((a)), /* start F */ \
|
|
+ LBA_to_M((a)+(l)), /* start M */ \
|
|
+ LBA_to_S((a)+(l)), /* start S */ \
|
|
+ LBA_to_F((a)+(l)), /* start F */ \
|
|
+ 10, /* ecc */ \
|
|
+ 0, 0 /* ? */ \
|
|
+)
|
|
+
|
|
+#define SCSI_TEN_BYTE(a,b,c,d,e,f,g,h,i,j) ((char []) {a,b,c,d,e,f,g,h,i,j})
|
|
+#define SCSI_MODE_SENSE_10(page, size) SCSI_TEN_BYTE( \
|
|
+ MODE_SENSE_10, /* MODE_SENSE */ \
|
|
+ 0x00, /* reserved */ \
|
|
+ page & 0x3F, /* page */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* MSB (0) */ \
|
|
+ size, /* sizeof(modesense - SG_OFF) */ \
|
|
+ 0 /* reserved */ \
|
|
+)
|
|
+#define SCSI_MODE_SELECT_10 SCSI_TEN_BYTE( \
|
|
+ MODE_SELECT_10, /* MODE_SELECT */ \
|
|
+ 0x10, /* no save page */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 12, /* sizeof(mode) */ \
|
|
+ 0 /* reserved */ \
|
|
+)
|
|
+#define SCSI_READ_TOC(track_number) SCSI_TEN_BYTE( \
|
|
+ READ_TOC, /* READ_TOC */ \
|
|
+ 0, /* MSF format */ \
|
|
+ 0, \
|
|
+ 0, \
|
|
+ 0, \
|
|
+ 0, \
|
|
+ track_number, /* start track */ \
|
|
+ 0, /* len msb */ \
|
|
+ 12, /* len lsb */ \
|
|
+ 0 /* flags */ \
|
|
+)
|
|
+/* a contribution from Boris for IMS cdd 522 */
|
|
+/* check this for ACER/Creative/Foo 525,620E,622E, etc? */
|
|
+#define CDD522_READ_TOC(track_number) SCSI_TEN_BYTE( \
|
|
+ 0xE5, /* CDD522_READ_TOC */ \
|
|
+ 0, 0, 0, 0, /* res */ \
|
|
+ track_number, /* start track */ \
|
|
+ 0, 0, 0, 0 /* ? */ \
|
|
+)
|
|
+#define SCSI_READ_10(fua, a, l) SCSI_TEN_BYTE( \
|
|
+ READ_10, /* READ_10 */ \
|
|
+ (fua?8:0), /* force unit access */ \
|
|
+ (a >> 24) & 0xff, /* lba byte 3 */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ 0, /* reserved */ \
|
|
+ (l >> 8) & 0xff, /* len byte 1 */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 0 /* control */ \
|
|
+)
|
|
+#define D4_READ_10(a, l) SCSI_TEN_BYTE( \
|
|
+ 0xD4, /* 0xD4 */ \
|
|
+ 0, /* ? */ \
|
|
+ 0, /* ? */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* ? */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 0 /* control */ \
|
|
+)
|
|
+#define D5_READ_10(a, l) SCSI_TEN_BYTE( \
|
|
+ 0xD5, /* 0xD5 */ \
|
|
+ 0, /* lun */ \
|
|
+ 0, /* ? */ \
|
|
+ (a >> 16) & 0xff, /* lba byte 2 */ \
|
|
+ (a >> 8) & 0xff, /* lba byte 1 */ \
|
|
+ a & 0xff, /* lba byte 0 */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* ? */ \
|
|
+ l & 0xff, /* len byte 0 */ \
|
|
+ 0 /* control */ \
|
|
+)
|
|
+
|
|
+
|
|
+#define SCSI_SIX_BYTE(a,b,c,d,e,f) ((char []) {a,b,c,d,e,f})
|
|
+#define SCSI_MODE_SENSE_6(page, size) SCSI_SIX_BYTE( \
|
|
+ MODE_SENSE, /* MODE_SENSE */ \
|
|
+ 0x00, /* return block descriptor/lun */ \
|
|
+ page & 0x3F, /* page */ \
|
|
+ 0, /* reserved */ \
|
|
+ size, /* sizeof(modesense - SG_OFF) */ \
|
|
+ 0 /* control */ \
|
|
+)
|
|
+#define SCSI_MODE_SELECT_6 SCSI_SIX_BYTE( \
|
|
+ MODE_SELECT, /* MODE_SELECT */ \
|
|
+ 0x10, /* no save page */ \
|
|
+ 0, /* reserved */ \
|
|
+ 0, /* reserved */ \
|
|
+ 12, /* sizeof(mode) */ \
|
|
+ 0 /* reserved */ \
|
|
+)
|
|
+#define SCSI_INQUIRY_6(len) SCSI_SIX_BYTE( \
|
|
+ INQUIRY, /* INQUIRY */ \
|
|
+ 0, 0, 0, /* ? */ \
|
|
+ len, 0 /* len, ? */ \
|
|
+)
|
|
+#define SCSI_TEST_UNIT_READY_6 SCSI_SIX_BYTE( \
|
|
+ TEST_UNIT_READY,/* TEST_UNIT_READY */ \
|
|
+ 0, 0, 0, 0, /* reserved */ \
|
|
+ 0 /* control */ \
|
|
+)
|
|
+#endif
|