$NetBSD: patch-cg,v 1.15 2018/09/27 19:23:09 ryoon Exp $

- fix ripping on NetBSD/amd64
- build fix on DragonFly
- build fix on NetBSD with SSP

--- interface/scsi_interface.c.orig	2008-09-11 20:33:30.000000000 +0000
+++ interface/scsi_interface.c
@@ -12,7 +12,16 @@
 #include "common_interface.h"
 #include "utils.h"
 #include <time.h>
-static int timed_ioctl(cdrom_drive *d, int fd, int command, void *arg){
+#include <sys/ioctl.h>
+
+#ifdef __NetBSD__
+#define SG_MAX_SENSE SENSEBUFLEN
+#define IOCTL_CMD unsigned long
+#else
+#define IOCTL_CMD int
+#endif
+
+static int timed_ioctl(cdrom_drive *d, int fd, IOCTL_CMD command, void *arg){
   struct timespec tv1;
   struct timespec tv2;
   int ret1=clock_gettime(d->private->clock,&tv1);
@@ -36,6 +45,7 @@ static void tweak_SG_buffer(cdrom_drive 
   int table, reserved, cur, err;
   char buffer[256];
 
+#ifdef __linux__
   /* 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
@@ -54,6 +64,10 @@ static void tweak_SG_buffer(cdrom_drive 
      implement working sg lists with SG_IO devices, so who knows... */
   if (ioctl(d->cdda_fd, SG_GET_SG_TABLESIZE, &table) < 0)
     table=1;
+#else
+  reserved = 32*1024;   /* ? */
+  table = 1;
+#endif
 
   sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t"
 	  "table entry size: %d bytes\n\t"
@@ -93,6 +107,7 @@ static void tweak_SG_buffer(cdrom_drive 
   cdmessage(d,buffer);
 }
 
+#if defined(__linux__) || defined(__DragonFly__)
 static void clear_garbage(cdrom_drive *d){
   fd_set fdset;
   struct timeval tv;
@@ -123,6 +138,7 @@ static void clear_garbage(cdrom_drive *d
     flag=1;
   }
 }
+#endif
 
 static int check_sbp_error(const unsigned char status,
 			   const unsigned char *sbp) {
@@ -172,6 +188,7 @@ static int check_sbp_error(const unsigne
   return 0;
 }
 
+#if defined(__linux__) || defined(__DragonFly__)
 /* process a complete scsi command. */
 static int sg2_handle_scsi_cmd(cdrom_drive *d,
 			       unsigned char *cmd,
@@ -356,7 +373,11 @@ static int sgio_handle_scsi_cmd(cdrom_dr
   hdr.timeout = 50000;
   hdr.interface_id = 'S';
   hdr.dxferp =  d->private->sg_buffer;
+#if defined(__DragonFly__)
+  hdr.flags = 0;
+#else
   hdr.flags = SG_FLAG_DIRECT_IO;  /* direct IO if we can get it */
+#endif
 
   /* scary buffer fill hack */
   if(bytecheck && out_size>in_size)
@@ -417,6 +438,161 @@ static int sgio_handle_scsi_cmd(cdrom_dr
   errno = 0;
   return 0;
 }
+#endif /* __linux__ */
+
+#ifdef __NetBSD__
+static int nb_handle_scsi_cmd(cdrom_drive *d,
+			       unsigned char *cmd,
+			       unsigned int cmd_len, 
+			       unsigned int in_size, 
+			       unsigned int out_size,       
+			       unsigned char bytefill,
+			       int bytecheck,
+			       unsigned char *sense_buffer){
+  int status = 0;
+  scsireq_t *sreq = (scsireq_t *)d->private->sg_hd;
+
+  memset(sense_buffer,0,SENSEBUFLEN);
+  memcpy(d->private->sg_buffer,cmd+cmd_len,in_size);
+
+  if (in_size && out_size) {
+    warnx("handle_scsi_cmd: in and out is not supported");
+    abort();
+  }
+  memset(sreq, 0, sizeof(scsireq_t));
+  sreq->cmdlen = cmd_len;
+  memcpy(sreq->cmd, cmd, cmd_len);
+  if (in_size) {
+    sreq->flags = SCCMD_WRITE;
+    sreq->databuf = d->private->sg_buffer;
+    sreq->datalen = in_size;
+  }
+  if (out_size) {
+    sreq->flags = SCCMD_READ;
+    sreq->databuf = d->private->sg_buffer;
+    sreq->datalen = out_size;
+    if(bytecheck)
+      memset(d->private->sg_buffer, bytefill, out_size); 
+  }
+  sreq->senselen = SENSEBUFLEN;
+  sreq->timeout = 60000;        /* 60s */
+
+  status = timed_ioctl(d, d->cdda_fd, SCIOCCOMMAND, (void *) sreq);
+  if (status < 0)
+    return(TR_ILLEGAL);
+  memcpy(sense_buffer,sreq->sense,SENSEBUFLEN);
+  status = check_sbp_error(sreq->status,sense_buffer);
+  if (status)
+    return status;
+
+  if(bytecheck && out_size){
+    long i,flag=0;
+    for(i=0;i<out_size;i++)
+      if(d->private->sg_buffer[i]!=bytefill){
+	flag=1;
+	break;
+      }
+    
+    if(!flag){
+      errno=EINVAL;
+      return(TR_ILLEGAL);
+    }
+  }
+
+  errno=0;
+  return 0;
+}
+#endif /* __NetBSD__ */
+
+#if defined(__FreeBSD__)
+static int fb_handle_scsi_cmd(cdrom_drive *d,
+			       unsigned char *cmd,
+			       unsigned int cmd_len, 
+			       unsigned int in_size, 
+			       unsigned int out_size,       
+			       unsigned char bytefill,
+			       int bytecheck,
+			       unsigned char *sense){
+	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->private->sg_buffer, cmd_len);
+
+	if (bytecheck && out_size == 0)
+		memset(d->private->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->private->sg_buffer + cmd_len : d->private->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 /* __FreeBSD__ */
 
 static int handle_scsi_cmd(cdrom_drive *d,
 			   unsigned char *cmd,
@@ -427,9 +603,17 @@ static int handle_scsi_cmd(cdrom_drive *
 			   int bytecheck,
 			   unsigned char *sense){
 
+#if defined(__linux__) || defined(__DragonFly__)
   if(d->interface == SGIO_SCSI || d->interface == SGIO_SCSI_BUGGY1)
     return sgio_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
   return sg2_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+#endif
+#ifdef __NetBSD__
+  return nb_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+#endif
+#if defined(__FreeBSD__)
+  return fb_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+#endif
 
 }
 
@@ -453,6 +637,7 @@ static int test_unit_ready(cdrom_drive *
   return 1;
 }
 
+#if defined(__linux__) || defined(__DragonFly__)
 static void reset_scsi(cdrom_drive *d){
   int arg,tries=0;
   d->enable_cdda(d,0);
@@ -471,6 +656,45 @@ static void reset_scsi(cdrom_drive *d){
   
   d->enable_cdda(d,1);
 }
+#endif
+
+#ifdef __NetBSD__
+static void reset_scsi(cdrom_drive *d){
+  int arg;
+  d->enable_cdda(d,0);
+
+  cdmessage(d,"sending SCSI reset... ");
+  if(ioctl(d->cdda_fd,CDIOCRESET,&arg))
+    cdmessage(d,"FAILED: EBUSY\n");
+  else
+    cdmessage(d,"OK\n");
+  
+  d->enable_cdda(d,1);
+}
+#endif
+
+#if 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
 
 static int mode_sense_atapi(cdrom_drive *d,int size,int page){ 
   unsigned char sense[SG_MAX_SENSE];
@@ -657,6 +881,7 @@ static int scsi_read_toc (cdrom_drive *d
   /* read the header first */
   unsigned char sense[SG_MAX_SENSE];
   unsigned char cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1, 0, 12, 0};
+  const char cmd_43[10] = { 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0};
   cmd[1]=d->lun<<5;
 
   if (handle_scsi_cmd (d,cmd,10, 0, 12,'\377',1,sense)){
@@ -674,7 +899,7 @@ static int scsi_read_toc (cdrom_drive *d
   }
 
   for (i = first; i <= last; i++){
-    memcpy(cmd, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+    memcpy(cmd, cmd_43, sizeof(cmd_43));
     cmd[1]=d->lun<<5;
     cmd[6]=i;
     
@@ -695,7 +920,7 @@ static int scsi_read_toc (cdrom_drive *d
     }
   }
 
-  memcpy(cmd, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+  memcpy(cmd, cmd_43, sizeof(cmd_43));
   cmd[1]=d->lun<<5;
   cmd[6]=0xAA;
     
@@ -745,7 +970,8 @@ static int scsi_read_toc2 (cdrom_drive *
   }
 
   for (i = 0; i < tracks; i++){
-    memcpy(cmd, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
+    const char cmd_e5[10] = { 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    memcpy(cmd, cmd_e5, sizeof(cmd_e5));
     cmd[5]=i+1;
     cmd[8]=255;
     
@@ -1587,6 +1813,7 @@ static void check_cache(cdrom_drive *d){
   }
 }
 
+#if defined(__linux__) || defined(__DragonFly__)
 static int check_atapi(cdrom_drive *d){
   int atapiret=-1;
   int fd = d->cdda_fd; /* check the device we'll actually be using to read */
@@ -1616,7 +1843,79 @@ static int check_atapi(cdrom_drive *d){
 
     return(d->is_atapi);
   }
-}  
+} 
+#endif
+
+#ifdef __NetBSD__
+static int check_atapi(cdrom_drive *d){
+  struct scsi_addr scaddr;
+  int fd = d->cdda_fd; /* check the device we'll actually be using to read */
+			  
+  cdmessage(d,"\nChecking for SCSI emulation...\n");
+
+  if (ioctl(fd,SCIOCIDENTIFY,&scaddr)){
+    cderror(d,"\tSG_EMULATED_HOST ioctl() failed!\n");
+    return(-1);
+  } else {
+    if(scaddr.type == TYPE_ATAPI){
+      cdmessage(d,"\tDrive is ATAPI\n");
+      d->is_atapi=1;
+    }else{
+      cdmessage(d,"\tDrive is SCSI\n");
+      d->is_atapi=0;
+    }
+
+    return(d->is_atapi);
+  }
+}
+#endif 
+
+#if 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){
   unsigned char *b;
@@ -1664,6 +1963,7 @@ static void check_exceptions(cdrom_drive
   }
 }
 
+#if !defined(__FreeBSD__) && !defined(__DragonFly__)
 /* request vendor brand and model */
 unsigned char *scsi_inquiry(cdrom_drive *d){
   unsigned char sense[SG_MAX_SENSE];
@@ -1675,6 +1975,7 @@ unsigned char *scsi_inquiry(cdrom_drive 
   }
   return (d->private->sg_buffer);
 }
+#endif
 
 int scsi_init_drive(cdrom_drive *d){
   int ret;
