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 #include #include -#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 * * 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_lenbytecheck && sgi->in_size+sgi->cmd_lenout_size){ long i,flag=0; - for(i=in_size;isg_buffer[i]!=bytefill){ + for(i=sgi->in_size; iout_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 + * + * macros to generate scsi commands. + * + ******************************************************************/ + +#ifndef _SCSI_CMDS_H +#define _SCSI_CMDS_H 1 +#include + +/* 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