Date: Tue, 11 Oct 2011 21:33:04 -0600 From: "Kenneth D. Merry" <ken@FreeBSD.org> To: Kevin Oberman <kob6558@gmail.com> Cc: ports@FreeBSD.org Subject: Re: audio/cdparanoia broken on -CURRENT, and probably on 9.0 Message-ID: <20111012033304.GA48367@nargothrond.kdm.org> In-Reply-To: <CAN6yY1vFXNRjGyA2NHtGcMhvgueRLvV=QeAYj6y1Qf1PjU1OrA@mail.gmail.com> References: <CAN6yY1vFXNRjGyA2NHtGcMhvgueRLvV=QeAYj6y1Qf1PjU1OrA@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
--qMm9M+Fa2AknHoGS Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Tue, Oct 11, 2011 at 15:52:35 -0700, Kevin Oberman wrote: > > On Fri, Oct 07, 2011 at 03:46:22 -0400, b. f. wrote: > > > Just a note to say that recent changes on -CURRENT (r225950, meaning > > > that it is probably broken on 9.0 after r226067) have broken > > > audio/cdparanoia, and it should be fixed or marked as BROKEN there. I > > > haven't filed a PR, or attempted to patch it yet -- I think that it > > > would be worthwhile to look into moving to 10.2, which has a large > > > number of improvements, although suffering from some Linuxisms. > > > > This will be easy to patch, using one of two methods: > > > > - change struct scsi_sense_data to struct scsi_sense_data_fixed > > or, better yet: > > - use scsi_extract_sense_len(), which will work for fixed or descriptor sense. > > Ken, > > OK. I have grepped through all of the cdparanoia sources and fine no > instances of scsi_sense_data. Where in the heck do I find it so I can > get this port built? 10.2 would be lovely, but I just need cdparanoia > on 9-stable quickly and I fear that hte package will no longer work > after r226067. There is no FreeBSD support in cdparanoia by default. It is patched in by the ports system. Go into the directory for the port, do a 'make fetch' and then 'make patch'. Then go into cdparanoia-III-alpha9.8/interface and copy the attached file on top of scsi_interface.c. I've checked that it compiles on a system running code before the change, but I think that change should work for systems before or after the change. Let me know whether it works for you. Ken -- Kenneth Merry ken@FreeBSD.ORG --qMm9M+Fa2AknHoGS Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="scsi_interface.c.cdparanoia.20111011.txt" /****************************************************************** * CopyPolicy: GNU Public License 2 applies * Original interface.c Copyright (C) 1994-1997 * Eissfeldt heiko@colossus.escape.de * Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu * FreeBSD porting (c) 2003 * Simon 'corecode' Schubert <corecode@corecode.ath.cx> * * Generic SCSI interface specific code. * ******************************************************************/ #include "low_interface.h" #include "common_interface.h" #include "utils.h" /* hook */ static int Dummy (cdrom_drive *d,int s){ return(0); } #include "drive_exceptions.h" static void tweak_SG_buffer(cdrom_drive *d){ int table,reserved; char buffer[256]; #ifdef Linux /* maximum transfer size? */ if(ioctl(d->cdda_fd,SG_GET_RESERVED_SIZE,&reserved)){ /* Up, guess not. */ cdmessage(d,"\tCould not get scatter/gather buffer size.\n"); return; } if(ioctl(d->cdda_fd,SG_GET_SG_TABLESIZE,&table))table=1; { int cur; 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; /* not too much; new kernels have trouble with DMA allocation, so be more conservative: 32kB max until I test more thoroughly */ cur=(cur>1024*32?1024*32:cur); 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); } /* Disable command queue; we don't need it, no reason to have it on */ reserved=0; if(ioctl(d->cdda_fd,SG_SET_COMMAND_Q,&reserved)){ cdmessage(d,"\tCouldn't disable command queue! Continuing anyway...\n"); } #elif defined(__FreeBSD__) d->nsectors = 26; /* FreeBSD only supports 64K I/O transfer size */ d->bigbuff = d->nsectors * CD_FRAMESIZE_RAW; sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n", d->nsectors,d->nsectors*CD_FRAMESIZE_RAW); cdmessage(d,buffer); #endif } #ifdef Linux 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); } #elif defined(__FreeBSD__) static void reset_scsi(cdrom_drive *d) { d->enable_cdda(d,0); d->ccb->ccb_h.func_code = XPT_RESET_DEV; d->ccb->ccb_h.timeout = 5000; cdmessage(d, "sending SCSI reset... "); if (cam_send_ccb(d->dev, d->ccb)) { cdmessage(d, "error sending XPT_RESET_DEV CCB"); } else { if (((d->ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) || ((d->ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT)) cdmessage(d,"OK\n"); else cdmessage(d,"FAILED\n"); } d->enable_cdda(d,1); } #endif #ifdef Linux 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; /* 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; } } #endif /* process a complete scsi command. */ #ifdef Linux 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){ int status = 0; struct sg_header *sg_hd=(struct sg_header *)d->sg; long writebytes=SG_OFF+cmd_len+in_size; /* generic scsi device services */ /* clear out any possibly preexisting garbage */ clear_garbage(d); memset(sg_hd,0,sizeof(sg_hd)); sg_hd->twelve_byte = cmd_len == 12; sg_hd->result = 0; sg_hd->reply_len = SG_OFF + 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 generic scsi driver (as of now) won't tell us; it hands back the uninitialized contents of the preallocated kernel buffer. We force this buffer to a known value via another bug (nonzero data 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); /* the size does not remove cmd_len due to the way the kernel driver copies buffers */ writebytes+=(out_size-in_size); } { /* Select on write with a 5 second timeout. This is a hack until a better error reporting layer is in place in alpha 10; right now, always print a message. */ fd_set fdset; struct timeval tv; FD_ZERO(&fdset); FD_SET(d->cdda_fd,&fdset); tv.tv_sec=60; /* Increased to 1m for plextor, as the drive will try to get through rough spots on its own and this can take time 19991129 */ tv.tv_usec=0; while(1){ int ret=select(d->cdda_fd+1,NULL,&fdset,NULL,&tv); if(ret>0)break; if(ret<0 && errno!=EINTR)break; if(ret==0){ fprintf(stderr,"\nSCSI transport error: timeout waiting to write" " packet\n\n"); return(TR_EWRITE); } } } sigprocmask (SIG_BLOCK, &(d->sigset), NULL ); errno=0; status = write(d->cdda_fd, sg_hd, writebytes ); if (status<0 || status != writebytes ) { sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL ); if(errno==0)errno=EIO; return(TR_EWRITE); } { /* Select on read (and write; this signals an error) with a 5 second timeout. This is a hack until a better error reporting layer is in place in alpha 10; right now, always print a message. */ fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(d->cdda_fd,&rset); tv.tv_sec=60; /* Increased to 1m for plextor, as the drive will try to get through rough spots on its own and this can take time 19991129 */ tv.tv_usec=0; while(1){ int ret=select(d->cdda_fd+1,&rset,NULL,NULL,&tv); if(ret<0 && errno!=EINTR)break; if(ret==0){ sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL ); fprintf(stderr,"\nSCSI transport error: timeout waiting to read" " packet\n\n"); return(TR_EREAD); } if(ret>0){ /* is it readable or something else? */ if(FD_ISSET(d->cdda_fd,&rset))break; sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL ); fprintf(stderr,"\nSCSI transport: error reading packet\n\n"); return(TR_EREAD); } } } errno=0; status = read(d->cdda_fd, sg_hd, SG_OFF + out_size); sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL ); if (status<0)return(TR_EREAD); if(status != SG_OFF + out_size || sg_hd->result){ 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); } } /* still not foolproof; the following doesn't guarantee that we got all the data, just that the command was not rejected. */ /* Why do this with the above sense stuff? For some reason, commands still get through. Perhaps no data comes back even though the target reports success? */ if(bytecheck && in_size+cmd_len<out_size){ long i,flag=0; for(i=in_size;i<out_size;i++) if(d->sg_buffer[i]!=bytefill){ flag=1; break; } if(!flag){ errno=EINVAL; return(TR_ILLEGAL); } } errno=0; return(0); } #elif defined(__FreeBSD__) static int handle_scsi_cmd(cdrom_drive *d, unsigned int cmd_len, unsigned int out_size, unsigned int in_size, unsigned char bytefill, int bytecheck) { int result; int error_code, sense_key, asc, ascq; bzero(&d->ccb->csio, sizeof(d->ccb->csio)); memcpy(d->ccb->csio.cdb_io.cdb_bytes, d->sg_buffer, cmd_len); if (bytecheck && out_size == 0) memset(d->sg_buffer, bytefill, in_size); cam_fill_csio(&d->ccb->csio, /* retries */ 0, /* cbfcnp */ NULL, /* flags */ CAM_DEV_QFRZDIS | (out_size ? CAM_DIR_OUT : CAM_DIR_IN), /* tag_action */ MSG_SIMPLE_Q_TAG, /* data_ptr */ out_size ? d->sg_buffer + cmd_len : d->sg_buffer, /* dxfer_len */ out_size ? out_size : in_size, /* sense_len */ SSD_FULL_SIZE, /* cdb_len */ cmd_len, /* timeout */ 60000); /* XXX */ if ((result = cam_send_ccb(d->dev, d->ccb)) < 0 || (d->ccb->ccb_h.status & CAM_STATUS_MASK) == 0 /* hack? */) return TR_EREAD; if ((d->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP && (d->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR) { fprintf (stderr, "\t\terror returned from SCSI command:\n" "\t\tccb->ccb_h.status == %d\n", d->ccb->ccb_h.status); errno = EIO; return TR_UNKNOWN; } if (d->ccb->csio.dxfer_len != in_size) { errno = EIO; return TR_EREAD; } scsi_extract_sense(&d->ccb->csio.sense_data, &error_code, &sense_key, &asc, &ascq); switch (error_code) { case SSD_CURRENT_ERROR: case SSD_DEFERRED_ERROR: #if (CAM_VERSION > 0x15) case SSD_DESC_CURRENT_ERROR: case SSD_DESC_DEFERRED_ERROR: #endif switch (sense_key) { case SSD_KEY_NO_SENSE: errno = EIO; return TR_UNKNOWN; case SSD_KEY_RECOVERED_ERROR: break; case SSD_KEY_NOT_READY: errno = EBUSY; return TR_BUSY; case SSD_KEY_MEDIUM_ERROR: errno = EIO; if ((asc == 0x0c) && (ascq == 0x09)) return TR_STREAMING; else return TR_MEDIUM; case SSD_KEY_HARDWARE_ERROR: errno = EIO; return TR_FAULT; case SSD_KEY_ILLEGAL_REQUEST: errno = EINVAL; return TR_ILLEGAL; default: errno = EIO; return TR_UNKNOWN; } default: break; } return 0; } #endif /* Group 1 (10b) command */ 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; if (handle_scsi_cmd (d, 10, 0, size+4,'\377',1)) return(1); { 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]; memmove(b+4,b+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); 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); } static int mode_sense(cdrom_drive *d,int size,int page){ if(d->is_atapi) return(mode_sense_atapi(d,size,page)); 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; 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 */ /* 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 */ /* do the scsi cmd */ return(handle_scsi_cmd (d,6, 12, 0,0,0)); } } /* 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); d->orgdens = d->sg_buffer[4]; return(d->orgsize = ((int)(d->sg_buffer[10])<<8)+d->sg_buffer[11]); } /* switch CDROM scsi drives to given sector size */ static int set_sectorsize (cdrom_drive *d,unsigned int secsize){ return(mode_select(d,d->orgdens,secsize)); } /* switch Toshiba/DEC and HP drives from/to cdda density */ int scsi_enable_cdda (cdrom_drive *d, int fAudioMode){ if (fAudioMode) { if(mode_select(d,d->density,CD_FRAMESIZE_RAW)){ if(d->error_retry) cderror(d,"001: Unable to set CDROM to read audio mode\n"); return(-1); } } else { if(mode_select(d,d->orgdens,d->orgsize)){ if(d->error_retry) cderror(d,"001: Unable to set CDROM to read audio mode\n"); return(-1); } } return(0); } typedef struct scsi_TOC { /* structure of scsi table of contents (cdrom) */ unsigned char reserved1; unsigned char bFlags; unsigned char bTrack; unsigned char reserved2; signed char start_MSB; unsigned char start_1; unsigned char start_2; unsigned char start_LSB; } scsi_TOC; /* read the table of contents from the cd and fill the TOC array */ /* Do it like the kernel ioctl driver; the 'all at once' approach fails on at least one Kodak drive. */ static int scsi_read_toc (cdrom_drive *d){ int i,first,last; unsigned tracks; /* READTOC, MSF format flag, res, res, res, res, Start track, len msb, len lsb, flags */ /* 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)){ cderror(d,"004: Unable to read table of contents header\n"); return(-4); } first=d->sg_buffer[2]; last=d->sg_buffer[3]; tracks=last-first+1; if (last > MAXTRK || first > MAXTRK || last<0 || first<0) { cderror(d,"003: CDROM reporting illegal number of tracks\n"); return(-3); } 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; if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){ 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)); } } 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)){ 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)); } d->cd_extra = FixupTOC(d,tracks+1); /* include lead-out */ 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; 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)){ 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]; 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; if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){ 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].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].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])))); d->cd_extra = FixupTOC(d,tracks+1); 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){ 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; 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){ 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_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_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_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_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_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_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_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); 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); } /* 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); 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); } 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); 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); } 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); 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); } static long scsi_read_map (cdrom_drive *d, void *p, long begin, long sectors, int (*map)(cdrom_drive *, void *, long, long)){ int retry_count,err; char *buffer=(char *)p; /* read d->nsectors at a time, max. */ sectors=(sectors>d->nsectors?d->nsectors:sectors); sectors=(sectors<1?1:sectors); retry_count=0; while(1) { if((err=map(d,(p?buffer:NULL),begin,sectors))){ if(d->report_all){ #ifdef Linux struct sg_header *sg_hd=(struct sg_header *)d->sg; #elif defined(__FreeBSD__) int error_code, sense_key, asc, ascq; #endif char b[256]; sprintf(b,"scsi_read error: sector=%ld length=%ld retry=%d\n", begin,sectors,retry_count); fputs(b, stderr); cdmessage(d,b); #if defined(__FreeBSD__) scsi_extract_sense(&d->ccb->csio.sense_data, &error_code, &sense_key, &asc, &ascq); #endif sprintf(b," Sense key: %x ASC: %x ASCQ: %x\n", #ifdef Linux (int)(sg_hd->sense_buffer[2]&0xf), (int)(sg_hd->sense_buffer[12]), (int)(sg_hd->sense_buffer[13])); #elif defined(__FreeBSD__) sense_key, asc, ascq); #endif fputs(b, stderr); cdmessage(d,b); sprintf(b," Transport error: %s\n",strerror_tr[err]); fputs(b, stderr); cdmessage(d,b); sprintf(b," System error: %s\n",strerror(errno)); fputs(b, stderr); cdmessage(d,b); } if(!d->error_retry)return(-7); switch(errno){ case EINTR: usleep(100); continue; case ENOMEM: /* D'oh. Possible kernel error. Keep limping */ usleep(100); if(sectors==1){ /* Nope, can't continue */ cderror(d,"300: Kernel memory error\n"); return(-300); } if(d->report_all){ char b[256]; sprintf(b,"scsi_read: kernel couldn't alloc %ld bytes. " "backing off...\n",sectors*CD_FRAMESIZE_RAW); cdmessage(d,b); } sectors--; continue; default: if(sectors==1){ if(errno==EIO) if(d->fua==-1) /* testing for FUA support */ return(-7); /* *Could* be I/O or media error. I think. If we're at 30 retries, we better skip this unhappy little sector. */ if(retry_count>MAX_RETRIES-1){ char b[256]; sprintf(b,"010: Unable to access sector %ld\n", begin); cderror(d,b); return(-10); } break; } /* Hmm. OK, this is just a tad silly. just in case this was a timeout and a reset happened, we need to set the drive back to cdda */ reset_scsi(d); } }else{ /* Did we get all the bytes we think we did, or did the kernel suck? */ if(buffer){ long i; for(i=sectors*CD_FRAMESIZE_RAW;i>1;i-=2) if(buffer[i-1]!='\177' || buffer[i-2]!='\177') break; i/=CD_FRAMESIZE_RAW; if(i!=sectors){ if(d->report_all){ char b[256]; sprintf(b,"scsi_read underrun: pos=%ld len=%ld read=%ld retry=%d\n", begin,sectors,i,retry_count); cdmessage(d,b); } reset_scsi(d); } if(i>0)return(i); }else break; } retry_count++; if(sectors==1 && retry_count>MAX_RETRIES){ cderror(d,"007: Unknown, unrecoverable error reading data\n"); return(-7); } if(sectors>1)sectors=sectors/2; d->enable_cdda(d,0); d->enable_cdda(d,1); } return(sectors); } long scsi_read_28 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_28)); } long scsi_read_A8 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_A8)); } long scsi_read_D4_10 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_D4_10)); } long scsi_read_D4_12 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_D4_12)); } long scsi_read_D5 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_D5)); } long scsi_read_D8 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_D8)); } long scsi_read_mmc (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_mmc)); } long scsi_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_mmc2)); } long scsi_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_mmc3)); } long scsi_read_msf (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_msf)); } long scsi_read_msf2 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_msf2)); } long scsi_read_msf3 (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_msf3)); } /* Some drives, given an audio read command, return only 2048 bytes of data as opposed to 2352 bytes. Look for bytess at the end of the single sector verification read */ static int count_2352_bytes(cdrom_drive *d){ long i; for(i=2351;i>=0;i--) if(d->sg_buffer[i]!=(unsigned char)'\177') return(((i+3)>>2)<<2); return(0); } static int verify_nonzero(cdrom_drive *d){ long i,flag=0; for(i=0;i<2352;i++) if(d->sg_buffer[i]!=0){ flag=1; break; } return(flag); } /* So many different read commands, densities, features... Verify that our selected 'read' command actually reads nonzero data, else search through other possibilities */ static int verify_read_command(cdrom_drive *d){ int i,j,k; int audioflag=0; int (*enablecommand) (struct cdrom_drive *d, int speed); long (*readcommand) (struct cdrom_drive *d, void *p, long begin, long sectors); unsigned char density; int16_t *buff=malloc(CD_FRAMESIZE_RAW); cdmessage(d,"Verifying CDDA command set...\n"); /* try the expected command set; grab the center of each track, look for data */ if(d->enable_cdda(d,1)==0){ for(i=1;i<=d->tracks;i++){ if(cdda_track_audiop(d,i)==1){ long firstsector=cdda_track_firstsector(d,i); long lastsector=cdda_track_lastsector(d,i); long sector=(firstsector+lastsector)>>1; audioflag=1; if(d->read_audio(d,buff,sector,1)>0){ if(count_2352_bytes(d)==2352){ cdmessage(d,"\tExpected command set reads OK.\n"); d->enable_cdda(d,0); free(buff); return(0); } } } } d->enable_cdda(d,0); } if(!audioflag){ cdmessage(d,"\tCould not find any audio tracks on this disk.\n"); return(-403); } { char *es="",*rs=""; d->bigendianp=-1; density=d->density; readcommand=d->read_audio; enablecommand=d->enable_cdda; /* No nonzeroes? D'oh. Exhaustive search */ cdmessage(d,"\tExpected command set FAILED!\n" "\tPerforming full probe for CDDA command set...\n"); /* loops: density/enable no, 0x0/org, 0x04/org, 0x82/org read command read_10 read_12 read_nec read_sony read_mmc read_mmc2 */ /* NEC test must come before sony; the nec drive expects d8 to be 10 bytes, and a 12 byte verson (Sony) crashes the drive */ for(j=0;j>=0;j++){ int densitypossible=1; switch(j){ case 0: d->read_audio=scsi_read_28; rs="28 0x,00"; break; case 1: d->read_audio=scsi_read_A8; rs="a8 0x,00"; break; case 2: d->read_audio=scsi_read_mmc; rs="be 00,10"; densitypossible=0; break; case 3: d->read_audio=scsi_read_mmc2; rs="be 00,f8"; densitypossible=0; break; case 4: d->read_audio=scsi_read_mmc3; rs="be 04,f8"; densitypossible=0; break; case 5: d->read_audio=scsi_read_msf; rs="b9 00,10"; densitypossible=0; break; case 6: d->read_audio=scsi_read_msf2; rs="b9 00,f8"; densitypossible=0; break; case 7: d->read_audio=scsi_read_msf3; rs="b9 04,f8"; densitypossible=0; break; case 8: d->read_audio=scsi_read_D4_10; rs="d4(10)0x"; break; case 9: d->read_audio=scsi_read_D4_12; rs="d4(12)0x"; break; case 10: d->read_audio=scsi_read_D5; rs="d5 0x,00"; break; case 11: d->read_audio=scsi_read_D8; rs="d8 0x,00"; j=-2; break; } for(i=0;i>=0;i++){ switch(i){ case 0: d->density=0; d->enable_cdda=Dummy; es="none "; if(!densitypossible)i=-2; /* short circuit MMC style commands */ break; case 1: d->density=0; d->enable_cdda=scsi_enable_cdda; es="yes/0x00"; break; case 2: d->density=0x04; d->enable_cdda=scsi_enable_cdda; es="yes/0x04"; break; case 3: d->density=0x82; d->enable_cdda=scsi_enable_cdda; es="yes/0x82"; case 4: d->density=0x81; d->enable_cdda=scsi_enable_cdda; es="yes/0x81"; i=-2; break; } cdmessage(d,"\ttest -> density: ["); cdmessage(d,es); cdmessage(d,"] command: ["); cdmessage(d,rs); cdmessage(d,"]\n"); { int densityflag=0; int rejectflag=0; int zeroflag=0; int lengthflag=0; if(d->enable_cdda(d,1)==0){ for(k=1;k<=d->tracks;k++){ if(cdda_track_audiop(d,k)==1){ long firstsector=cdda_track_firstsector(d,k); long lastsector=cdda_track_lastsector(d,k); long sector=(firstsector+lastsector)>>1; if(d->read_audio(d,buff,sector,1)>0){ if((lengthflag=count_2352_bytes(d))==2352){ if(verify_nonzero(d)){ cdmessage(d,"\t\tCommand set FOUND!\n"); free(buff); d->enable_cdda(d,0); return(0); }else{ zeroflag++; } } }else{ rejectflag++; break; } } } d->enable_cdda(d,0); }else{ densityflag++; } if(densityflag) cdmessage(d,"\t\tDrive rejected density set\n"); if(rejectflag){ char buffer[256]; sprintf(buffer,"\t\tDrive rejected read command packet(s)\n"); cdmessage(d,buffer); } if(lengthflag>0 && lengthflag<2352){ char buffer[256]; sprintf(buffer,"\t\tDrive returned at least one packet, but with\n" "\t\tincorrect size (%d)\n",lengthflag); cdmessage(d,buffer); } if(zeroflag){ char buffer[256]; sprintf(buffer,"\t\tDrive returned %d packet(s), but contents\n" "\t\twere entirely zero\n",zeroflag); cdmessage(d,buffer); } } } } /* D'oh. */ d->density=density; d->read_audio=readcommand; d->enable_cdda=enablecommand; cdmessage(d,"\tUnable to find any suitable command set from probe;\n" "\tdrive probably not CDDA capable.\n"); cderror(d,"006: Could not read any data from drive\n"); } free(buff); return(-6); } static void check_fua_bit(cdrom_drive *d){ int16_t *buff=malloc(CD_FRAMESIZE_RAW); long i; if(d->read_audio==scsi_read_mmc)return; if(d->read_audio==scsi_read_mmc2)return; if(d->read_audio==scsi_read_mmc3)return; cdmessage(d,"This command set may use a Force Unit Access bit."); cdmessage(d,"\nChecking drive for FUA bit support...\n"); d->enable_cdda(d,1); d->fua=1; for(i=1;i<=d->tracks;i++){ if(cdda_track_audiop(d,i)==1){ long firstsector=cdda_track_firstsector(d,i); long lastsector=cdda_track_lastsector(d,i); long sector=(firstsector+lastsector)>>1; if(d->read_audio(d,buff,sector,1)>0){ cdmessage(d,"\tDrive accepted FUA bit.\n"); d->enable_cdda(d,0); free(buff); return; } } } d->fua=0; cdmessage(d,"\tDrive rejected FUA bit.\n"); free(buff); return; } #ifdef Linux static int check_atapi(cdrom_drive *d){ 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 */ cdmessage(d,"\nChecking for SCSI emulation...\n"); if (ioctl(fd,SG_EMULATED_HOST,&atapiret)){ cderror(d,"\tSG_EMULATED_HOST ioctl() failed!\n"); return(-1); } else { 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)) cderror(d,"\tCouldn't disable kernel command translation layer\n"); d->is_atapi=1; }else{ cdmessage(d,"\tDrive is SCSI\n"); d->is_atapi=0; } return(d->is_atapi); } } #elif defined(__FreeBSD__) static int check_atapi(cdrom_drive *d) { bzero(&(&d->ccb->ccb_h)[1], sizeof(d->ccb->cpi) - sizeof(d->ccb->ccb_h)); d->ccb->ccb_h.func_code = XPT_PATH_INQ; cdmessage(d, "\nChecking for ATAPICAM...\n"); if (cam_send_ccb(d->dev, d->ccb) < 0) { cderror(d, "\terror sending XPT_PATH_INQ CCB: "); cderror(d, cam_errbuf); cderror(d, "\n"); return -1; } if ((d->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { cderror(d, "\tXPT_PATH_INQ CCB failed: "); cderror(d, cam_errbuf); cderror(d, "\n"); return -1; } /* * if the bus device name is `ata', we're (obviously) * running ATAPICAM. * same for the new ahci(4) and siis(4) drivers and future others * which use SATA transport too... */ if (strncmp(d->ccb->cpi.dev_name, "ata", 3) == 0 || #if __FreeBSD_version >= 800102 d->ccb->cpi.transport == XPORT_SATA || #endif d->ccb->cpi.transport == XPORT_ATA) { cdmessage(d, "\tDrive is ATAPI (using ATAPICAM or direct CAM (S)ATA transport)\n"); d->is_atapi = 1; } else { cdmessage(d, "\tDrive is SCSI\n"); d->is_atapi = 0; } return d->is_atapi; } #endif static int check_mmc(cdrom_drive *d){ char *b; cdmessage(d,"\nChecking for MMC style command set...\n"); d->is_mmc=0; if(mode_sense(d,22,0x2A)==0){ b=d->sg_buffer; b+=b[3]+4; if((b[0]&0x3F)==0x2A){ /* MMC style drive! */ d->is_mmc=1; if(b[1]>=4){ if(b[5]&0x1){ cdmessage(d,"\tDrive is MMC style\n"); return(1); }else{ cdmessage(d,"\tDrive is MMC, but reports CDDA incapable.\n"); cdmessage(d,"\tIt will likely not be able to read audio data.\n"); return(1); } } } } cdmessage(d,"\tDrive does not have MMC CDDA support\n"); return(0); } static void check_exceptions(cdrom_drive *d,exception *list){ int i=0; while(list[i].model){ if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){ if(list[i].density)d->density=list[i].density; if(list[i].enable)d->enable_cdda=list[i].enable; if(list[i].read)d->read_audio=list[i].read; if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp; return; } i++; } } #ifdef Linux /* request vendor brand and model */ unsigned char *scsi_inquiry(cdrom_drive *d){ memcpy(d->sg_buffer,(char[]){ 0x12,0,0,0,56,0},6); if(handle_scsi_cmd(d,6, 0, 56,'\377',1)) { cderror(d,"008: Unable to identify CDROM model\n"); return(NULL); } return (d->sg_buffer); } #endif int scsi_init_drive(cdrom_drive *d){ int ret; check_atapi(d); check_mmc(d); /* generic Sony type defaults; specialize from here */ d->density = 0x0; d->enable_cdda = Dummy; d->read_audio = scsi_read_D8; d->fua=0x0; if(d->is_atapi)d->lun=0; /* it should already be; just to make sure */ if(d->is_mmc){ d->read_audio = scsi_read_mmc2; d->bigendianp=0; check_exceptions(d,mmc_list); }else{ if(d->is_atapi){ /* Not MMC maybe still uses 0xbe */ d->read_audio = scsi_read_mmc2; d->bigendianp=0; check_exceptions(d,atapi_list); }else{ check_exceptions(d,scsi_list); } } if(!d->is_atapi)set_sectorsize(d,2048); /* we really do want the sector size at 2048 to begin.*/ d->enable_cdda(d,0); d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 : scsi_read_toc; d->set_speed = NULL; if(!d->is_atapi){ unsigned sector_size= get_orig_sectorsize(d); if(sector_size<2048 && set_sectorsize(d,2048)) d->adjust_ssize = 2048 / sector_size; else d->adjust_ssize = 1; }else d->adjust_ssize = 1; d->tracks=d->read_toc(d); 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; #ifdef Linux d->sg=realloc(d->sg,d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128); d->sg_buffer=d->sg+SG_OFF; #elif defined(__FreeBSD__) d->sg_buffer = realloc(d->sg_buffer, d->nsectors * CD_FRAMESIZE_RAW); #endif d->report_all=1; return(0); } --qMm9M+Fa2AknHoGS--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20111012033304.GA48367>