$OpenBSD: patch-interface_scsi_interface_c,v 1.4 2007/10/27 15:01:53 espie Exp $
--- interface/scsi_interface.c.orig	Sat Mar 24 02:15:46 2001
+++ interface/scsi_interface.c	Sat Oct 27 16:57:49 2007
@@ -23,6 +23,7 @@ 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. */
@@ -31,6 +32,10 @@ static void tweak_SG_buffer(cdrom_drive *d){
   }
 
   if(ioctl(d->cdda_fd,SG_GET_SG_TABLESIZE,&table))table=1;
+#else
+  reserved = 32*1024;  /* ? */
+  table = 1;
+#endif
   {
     int cur;
 
@@ -53,20 +58,27 @@ static void tweak_SG_buffer(cdrom_drive *d){
     cdmessage(d,buffer);
   } 
 
+#ifdef __linux__
   /* 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");
   }
-
+#endif
 }
 
 static void reset_scsi(cdrom_drive *d){
   int arg;
   d->enable_cdda(d,0);
 
+#ifdef __linux__
   cdmessage(d,"sending SG SCSI reset... ");
   if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
+#endif
+#if defined (__NetBSD__) || defined (__OpenBSD__)
+  cdmessage(d,"sending SCSI reset... ");
+  if(ioctl(d->cdda_fd,CDIOCRESET,&arg))
+#endif
     cdmessage(d,"FAILED: EBUSY\n");
   else
     cdmessage(d,"OK\n");
@@ -74,6 +86,7 @@ static void reset_scsi(cdrom_drive *d){
   d->enable_cdda(d,1);
 }
 
+#ifdef __linux__
 static void clear_garbage(cdrom_drive *d){
   fd_set fdset;
   struct timeval tv;
@@ -104,6 +117,7 @@ static void clear_garbage(cdrom_drive *d){
     flag=1;
   }
 }
+#endif
 
 /* process a complete scsi command. */
 static int handle_scsi_cmd(cdrom_drive *d,
@@ -114,11 +128,16 @@ static int handle_scsi_cmd(cdrom_drive *d,
 			   unsigned char bytefill,
 			   int bytecheck){
   int status = 0;
+#ifdef __linux__
   struct sg_header *sg_hd=(struct sg_header *)d->sg;
   long writebytes=SG_OFF+cmd_len+in_size;
-
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+  scsireq_t *sreq = (scsireq_t *)d->sg;
+#endif
   /* generic scsi device services */
 
+#ifdef __linux__
   /* clear out any possibly preexisting garbage */
   clear_garbage(d);
 
@@ -213,8 +232,38 @@ static int handle_scsi_cmd(cdrom_drive *d,
       }
     }
   }
+#endif /* __linux__ */
 
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+  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, d->sg_buffer, cmd_len);
+  if (in_size) {
+    sreq->flags = SCCMD_WRITE;
+    sreq->databuf = d->sg_buffer + cmd_len;
+    sreq->datalen = in_size;
+  }
+  if (out_size) {
+    sreq->flags = SCCMD_READ;
+    sreq->databuf = d->sg_buffer;
+    sreq->datalen = out_size;
+    if(bytecheck)
+      memset(d->sg_buffer, bytefill, out_size); 
+  }
+  sreq->senselen = SENSEBUFLEN;
+  sreq->timeout = 10000;       /* 10s */
+
+  status = ioctl(d->cdda_fd, SCIOCCOMMAND, (void *) sreq);
+  if (status < 0)
+    return(TR_ILLEGAL);
+#endif
+
   errno=0;
+#ifdef __linux__
   status = read(d->cdda_fd, sg_hd, SG_OFF + out_size);
   sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
 
@@ -229,6 +278,13 @@ static int handle_scsi_cmd(cdrom_drive *d,
     char key=sg_hd->sense_buffer[2]&0xf;
     char ASC=sg_hd->sense_buffer[12];
     char ASCQ=sg_hd->sense_buffer[13];
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+  if (sreq->sense[0]){
+    char key = sreq->sense[2]&0xf;
+    char ASC = sreq->sense[12];
+    char ASCQ = sreq->sense[13];
+#endif
     switch(key){
     case 0:
       if(errno==0)errno=EIO;
@@ -266,9 +322,19 @@ static int handle_scsi_cmd(cdrom_drive *d,
      commands still get through.  Perhaps no data comes back even
      though the target reports success? */
 
+#ifdef __linux__
   if(bytecheck && in_size+cmd_len<out_size){
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+  if(bytecheck && out_size){
+#endif
     long i,flag=0;
+#ifdef __linux__
     for(i=in_size;i<out_size;i++)
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+    for(i=0;i<out_size;i++)
+#endif
       if(d->sg_buffer[i]!=bytefill){
 	flag=1;
 	break;
@@ -600,6 +666,24 @@ static int scsi_read_toc2 (cdrom_drive *d){
   return(tracks);
 }
 
+/* Set operating speed */
+static int scsi_setspeed(cdrom_drive *d, int speed)
+{
+  if (speed == 0)   
+    speed = 0xffff;            /* maximum speed */
+  else if (speed < 176)
+    speed *= 176;
+
+  memset(d->sg_buffer, 0, 12);
+  d->sg_buffer[0] = 0xbb;      /* set speed */
+  d->sg_buffer[2] = speed >> 8;
+  d->sg_buffer[3] = speed;
+  d->sg_buffer[4] = -1;
+  d->sg_buffer[5] = -1;
+  return handle_scsi_cmd(d, 12, 0, 0, 0, 0);
+}
+
+
 /* 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){
@@ -833,16 +917,28 @@ static long scsi_read_map (cdrom_drive *d, void *p, lo
   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;
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+       scsireq_t *sreq=(scsireq_t *)d->sg;
+#endif
 	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",
+#ifdef __linux__
 		(int)(sg_hd->sense_buffer[2]&0xf),
 		(int)(sg_hd->sense_buffer[12]),
 		(int)(sg_hd->sense_buffer[13]));
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+               (int)(sreq->sense[2]&0xf),
+               (int)(sreq->sense[12]),
+               (int)(sreq->sense[13]));
+#endif
 	cdmessage(d,b);
 	sprintf(b,"                 Transport error: %s\n",strerror_tr[err]);
 	cdmessage(d,b);
@@ -852,9 +948,16 @@ static long scsi_read_map (cdrom_drive *d, void *p, lo
 	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",
+#ifdef __linux__
 		(int)(sg_hd->sense_buffer[2]&0xf),
 		(int)(sg_hd->sense_buffer[12]),
 		(int)(sg_hd->sense_buffer[13]));
+#endif
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+               (int)(sreq->sense[2]&0xf),
+               (int)(sreq->sense[12]),
+               (int)(sreq->sense[13]));
+#endif
 	fprintf(stderr,"                 Transport error: %s\n",strerror_tr[err]);
 	fprintf(stderr,"                 System error: %s\n",strerror(errno));
       }
@@ -1308,21 +1411,37 @@ static void check_fua_bit(cdrom_drive *d){
 }
 
 static int check_atapi(cdrom_drive *d){
+#ifdef __linux__
   int atapiret=-1;
+#endif
+#if defined (__NetBSD__) || defined (__OpenBSD__)
+  struct scsi_addr scaddr;
+#endif
   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");
 
+#ifdef __linux__
   if (ioctl(fd,SG_EMULATED_HOST,&atapiret)){
+#endif
+#if defined (__NetBSD__) || defined (__OpenBSD__)
+  if(ioctl(fd,SCIOCIDENTIFY,&scaddr)){
+#endif
     cderror(d,"\tSG_EMULATED_HOST ioctl() failed!\n");
     return(-1);
   } else {
+#ifdef __linux__
     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");
+#endif
+#if defined (__NetBSD__) || defined (__OpenBSD__)
+    if(scaddr.type == TYPE_ATAPI){
+      cdmessage(d,"\tDrive is ATAPI\n");
+#endif
       d->is_atapi=1;
     }else{
       cdmessage(d,"\tDrive is SCSI\n");
@@ -1434,7 +1553,7 @@ int scsi_init_drive(cdrom_drive *d){
 
   d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 : 
     scsi_read_toc;
-  d->set_speed = NULL;
+  d->set_speed = scsi_setspeed;
   
 
   if(!d->is_atapi){
