home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / FreeBSD / scsi_freebsd.cpp next >
C/C++ Source or Header  |  1999-10-03  |  18KB  |  744 lines

  1. /*
  2.  *  scsi_freebsd.cpp - SCSI Manager, FreeBSD SCSI Driver implementation
  3.  *  Copyright (C) 1999 Orlando Bassotto
  4.  *
  5.  *  Basilisk II (C) 1997-1999 Christian Bauer
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  *
  21.  *  History:
  22.  *    29-Jun-1999 Started
  23.  *    05-Jul-1999 Changed from array to queue removing the limit of 8 
  24.  *                devices.
  25.  *                Implemented old SCSI management for FreeBSD 2.x.
  26.  *                (Note: This implementation hasn't been tested;
  27.  *                 I don't own anymore a machine with FreeBSD 2.x,
  28.  *                 so if something goes wrong, please mail me to
  29.  *                 future@mediabit.net).
  30.  */
  31.  
  32. #include <sys/ioctl.h>
  33. #include <sys/types.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <unistd.h>
  38. #include <fcntl.h>
  39. #include <ctype.h>
  40. #include <errno.h>
  41. #include <err.h>
  42.  
  43. #ifdef CAM
  44. #include <cam/cam.h>
  45. #include <cam/cam_debug.h>
  46. #include <cam/cam_ccb.h>
  47. #include <cam/scsi/scsi_all.h>
  48. #include <cam/scsi/scsi_da.h>
  49. #include <cam/scsi/scsi_pass.h>
  50. #include <cam/scsi/scsi_message.h>
  51. #include <camlib.h>
  52. #else /* !CAM */
  53. #include <sys/scsiio.h>
  54. #include <scsi.h>
  55. #endif /* !CAM */
  56.  
  57. #include "sysdeps.h"
  58. #include "main.h"
  59. #include "prefs.h"
  60. #include "user_strings.h"
  61. #include "scsi.h"
  62.  
  63. #define DEBUG 0
  64. #include "debug.h"
  65.  
  66.  
  67. #undef u_int8_t
  68. #define u_int8_t unsigned char
  69.  
  70. typedef struct _SCSIDevice {
  71.     int        controller;        // SCSI Controller
  72.     int        controller_bus;        // SCSI Controller Bus
  73.     char        controller_name[33];    // SCSI Controller name
  74.      int        mac_unit;        // Macintosh SCSI ID (remapped)
  75.     int        faked_controller;    // "Faked" SCSI Controller (Always 0)
  76.     int        faked_unit;        // "Faked" SCSI ID
  77.     int        unit;            // Real SCSI ID
  78.     int        lun;            // Real SCSI LUN
  79.     u_int8_t    vendor[16];        // SCSI Vendor
  80.     u_int8_t    product[48];        // SCSI Product
  81.     u_int8_t    revision[16];        // SCSI Revision
  82.     char        device[33];        // SCSI Device
  83. #ifdef CAM
  84.     char        pass_device[33];    // SCSI Pass Device
  85. #else /* !CAM */
  86.     int        dev_fd;            // Device File Descriptor
  87. #endif /* !CAM */
  88.     void*        dev_ptr;        // Pointer to CAM/SCSI structure
  89.     bool        enabled;        // Device enabled ?
  90.     struct _SCSIDevice* next;        // Pointer to the next device
  91. } SCSIDevice;
  92.  
  93. static int nDevices = 0;
  94. static SCSIDevice* Devices = NULL;
  95.  
  96. static uint32 buffer_size;
  97. static uint8* buffer = NULL;
  98.  
  99. static uint8 the_cmd[12];
  100. static int the_cmd_len;
  101.  
  102. static SCSIDevice* CurrentDevice = NULL;
  103.  
  104. inline static SCSIDevice* _GetSCSIDeviceByID(int id)
  105. {
  106.     SCSIDevice* aux = Devices;
  107.     while(aux) {
  108.         if(aux->faked_unit==id) {
  109.             return aux;
  110.         }
  111.         aux = aux->next;
  112.     }
  113.     return NULL;
  114. }
  115.  
  116. inline static SCSIDevice* _GetSCSIDeviceByIDLUN(int id, int lun)
  117. {
  118.     SCSIDevice* aux = Devices;
  119.     while(aux) {
  120.         if(aux->faked_unit==id&&aux->lun==lun) {
  121.             return aux;
  122.         }
  123.         aux = aux->next;
  124.     }
  125.     return NULL;
  126. }
  127.  
  128. inline static SCSIDevice* _GetSCSIDeviceByMacID(int id)
  129. {
  130.     SCSIDevice* aux = Devices;
  131.     while(aux) {
  132.         if(aux->mac_unit==id) {
  133.             return aux;
  134.         }
  135.         aux = aux->next;
  136.     }
  137.     return NULL;
  138. }
  139.  
  140. inline static SCSIDevice* _GetSCSIDeviceByMacIDLUN(int id, int lun)
  141. {
  142.     SCSIDevice* aux = Devices;
  143.     while(aux) {
  144.         if(aux->mac_unit==id&&aux->lun==lun) {
  145.             return aux;
  146.         }
  147.         aux = aux->next;
  148.     }
  149.     return NULL;
  150. }
  151.  
  152. inline static SCSIDevice* _AllocNewDevice()
  153. {
  154.     SCSIDevice* aux;
  155.     
  156.     aux = new SCSIDevice;
  157.     if(aux==NULL) return NULL;
  158.     memset(aux, 0, sizeof(SCSIDevice));
  159.     aux->next = Devices;
  160.     Devices = aux;
  161.     return aux;
  162. }
  163.  
  164. #ifdef CAM
  165. inline static struct cam_device* _GetCurrentSCSIDevice()
  166. {
  167.     if(CurrentDevice==NULL) return NULL;
  168.     
  169.     return (struct cam_device*)CurrentDevice->dev_ptr;
  170. }
  171. #else /* !CAM */
  172. inline static struct scsireq* _GetCurrentSCSIDevice()
  173. {
  174.     if(CurrentDevice==NULL) return NULL;
  175.     
  176.     return (struct scsireq*)CurrentDevice->dev_ptr;
  177. }
  178. #endif /* !CAM */
  179.  
  180. /*
  181.  * _Build_SCSI_Controller()
  182.  *
  183.  * This function builds a virtual SCSI Controller (Controller=0)
  184.  * where keeps all the devices found, this is due the fact
  185.  * I have two SCSI controllers in my PC. :-)
  186.  * Use scsidump in contrib/ to see how is remapped your 
  187.  * SCSI device (only if you have more than one controller, 
  188.  * that's for sure :-).
  189.  * If you have only one controller, remapping does not take act.
  190.  */
  191.  
  192. #define GET_FREE_ID(id) \
  193.     { \
  194.         for(int x=0;x<32;x++) { \
  195.             if(!(busyIDs&(1<<(x+1)))) { \
  196.                 id = x; \
  197.                 break; \
  198.             } \
  199.         } \
  200.     }
  201.     
  202. static void _Build_SCSI_Controller()
  203. {
  204.     unsigned int id = 0;
  205.     unsigned long long busyIDs = 0x0ll;
  206.     SCSIDevice* aux, * dev;
  207.         
  208.     // What IDs are busy?
  209.     dev = Devices;
  210.     while(dev) {
  211.         dev->enabled = false;
  212.         dev->faked_controller = 0;
  213.         dev->faked_unit = dev->unit;
  214.         busyIDs |= (1 << (dev->unit+1));
  215.         dev = dev->next;
  216.     }
  217.     
  218.     // Find out the duplicate IDs and remap them
  219.     dev = Devices, aux = NULL;
  220.     while(dev) {
  221.         aux = dev;
  222.         while(aux) {
  223.             SCSIDevice* dev1, * dev2;
  224.             
  225.             dev1 = dev, dev2 = aux;
  226.             
  227.             if(dev1->controller!=dev2->controller&&
  228.                 dev1->unit==dev2->unit) {
  229.                 int free_id;
  230.                 GET_FREE_ID(free_id);
  231.                 busyIDs |= (1<<(free_id+1));
  232.                 dev1->faked_unit = free_id;
  233.             }
  234.             aux = aux->next;
  235.         }
  236.         dev = dev->next;
  237.     }
  238.     
  239.     // Now reorder the queue 
  240. #if 0
  241.     dev = Devices;
  242.     while(dev) {
  243.         aux = dev;
  244.         while(aux) {
  245.             SCSIDevice* dev1, * dev2;
  246.     
  247.             dev1 = dev, dev2 = aux;
  248.             if(dev1->faked_unit>dev2->faked_unit) {
  249.                 SCSIDevice tmp;
  250.                 
  251.                 memcpy(&tmp, dev1, sizeof(SCSIDevice));
  252.                 memcpy(dev1, dev2, sizeof(SCSIDevice));
  253.                 memcpy(dev2, &tmp, sizeof(SCSIDevice));
  254.             }
  255.             aux = aux->next;
  256.         }
  257.         dev = dev->next;
  258.     }
  259. #endif
  260.  
  261.     // Now open the selected SCSI devices :-)
  262.     for(int n=0;n<8;n++) {
  263.         char tmp[25];
  264.         
  265.         snprintf(tmp, sizeof(tmp), "scsi%d", n);
  266.         const char* scsi = PrefsFindString(tmp);
  267.         if(scsi) {
  268.             int id, lun;
  269.             
  270.             // The format is: RemappedID (or FakedID)/LUN
  271.             sscanf(scsi, "%d/%d", &id, &lun);
  272.             
  273.             SCSIDevice* dev = _GetSCSIDeviceByIDLUN(id, lun);
  274.             if(dev==NULL) continue;
  275.             dev->enabled = true;
  276.             dev->mac_unit = n;
  277.  
  278. #ifdef CAM
  279.             struct cam_device* cam;
  280.  
  281.             cam = cam_open_btl(dev->controller,
  282.                 dev->unit,
  283.                 dev->lun, O_RDWR, NULL);
  284.             if(cam==NULL) {
  285.                 fprintf(stderr, "Failed to open %d:%d:%d = %s!!!\n",
  286.                     dev->controller, dev->unit, dev->lun,
  287.                     cam_errbuf);
  288.             }
  289.             dev->dev_ptr = (void*)cam;
  290. #else /* !CAM */
  291.             dev->dev_fd = scsi_open(dev->device, O_RDWR);
  292.             if(dev->dev_fd<0) {
  293.                 perror("Failed to open %d:%d:%d");
  294.             }
  295.             else {
  296.                 dev->dev_ptr = (void*)scsireq_new();
  297.             }
  298. #endif /* !CAM */
  299.         }
  300.     }
  301. }    
  302.  
  303.     
  304. /*
  305.  *  Initialization
  306.  */
  307.  
  308. void SCSIInit(void)
  309. {
  310.     // Finds the SCSI hosts in the system filling the SCSIDevices queue.
  311.     // "Stolen" from camcontrol.c
  312.     //    Copyright (C) 1997-99 Kenneth D. Merry
  313.     // Old SCSI detection "stolen" from scsi.c
  314.     //    Copyright (C) 1993 Julian Elischer
  315.         //
  316.     int bufsize, fd;
  317.     int need_close = 0;
  318.     int error = 0;
  319.     int skip_device = 0;
  320.     SCSIDevice* Dev, * dev, * PrevDev = NULL;
  321.     
  322.     nDevices = 0;
  323.  
  324.     if(PrefsFindBool("noscsi"))
  325.         goto no_scsi;
  326.  
  327. #ifdef CAM
  328.     union ccb ccb;
  329.     if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
  330.         fprintf(stderr, "WARNING: Cannot open CAM device %s (%s)\n", XPT_DEVICE, strerror(errno));
  331.         goto no_scsi;
  332.     }
  333.     
  334.     memset(&(&ccb.ccb_h)[1], 0, sizeof(struct ccb_dev_match)-sizeof(struct ccb_hdr));
  335.     ccb.ccb_h.func_code = XPT_DEV_MATCH;
  336.     bufsize = sizeof(struct dev_match_result) * 100;
  337.     ccb.cdm.match_buf_len = bufsize;
  338.     ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
  339.     ccb.cdm.num_matches = 0;
  340.     
  341.     ccb.cdm.num_patterns = 0;
  342.     ccb.cdm.pattern_buf_len = 0;
  343.     
  344.     do {
  345.         Dev = _AllocNewDevice();    
  346.         if(ioctl(fd, CAMIOCOMMAND, &ccb)==-1) {
  347.             fprintf(stderr, "Error sending CAMIOCOMMAND ioctl\n");
  348.             return;
  349.         }
  350.         
  351.         if((ccb.ccb_h.status != CAM_REQ_CMP)
  352.         || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
  353.          && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
  354.              fprintf(stderr, "Got CAM error %#x, CDM error %d\n",
  355.                  ccb.ccb_h.status, ccb.cdm.status);
  356.              return;
  357.         }
  358.          
  359.         char current_controller_name[33];
  360.         int current_controller = -1;
  361.         for(int i=0;i<ccb.cdm.num_matches;i++) {
  362.             switch(ccb.cdm.matches[i].type) {
  363.             case DEV_MATCH_BUS:
  364.             {
  365.                 struct bus_match_result* bus_result;
  366.                                 
  367.                 bus_result = &ccb.cdm.matches[i].result.bus_result;
  368.                 
  369.                 if(bus_result->path_id==-1) break;
  370.                 Dev->controller = bus_result->path_id;
  371.                 snprintf(Dev->controller_name, sizeof(Dev->controller_name), "%s%d", 
  372.                     bus_result->dev_name,
  373.                     bus_result->unit_number);
  374.                 strncpy(current_controller_name, Dev->controller_name, sizeof(current_controller_name));
  375.                 current_controller = Dev->controller;
  376.                 Dev->controller_bus = bus_result->bus_id;
  377.                 break;
  378.             }
  379.             case DEV_MATCH_DEVICE:
  380.             {
  381.                 struct device_match_result* dev_result;
  382.                 char tmpstr[256];
  383.                 
  384.                 dev_result = &ccb.cdm.matches[i].result.device_result;
  385.                 if(current_controller==-1||dev_result->target_id==-1) {
  386.                     skip_device = 1;
  387.                     break;
  388.                 }
  389.                 else skip_device = 0;
  390.                 
  391.                 cam_strvis(Dev->vendor, (u_int8_t*)dev_result->inq_data.vendor,
  392.                     sizeof(dev_result->inq_data.vendor),
  393.                     sizeof(Dev->vendor));
  394.                 cam_strvis(Dev->product, (u_int8_t*)dev_result->inq_data.product,
  395.                     sizeof(dev_result->inq_data.product),
  396.                     sizeof(Dev->product));
  397.                 cam_strvis(Dev->revision, (u_int8_t*)dev_result->inq_data.revision,
  398.                     sizeof(dev_result->inq_data.revision),
  399.                     sizeof(Dev->revision));
  400.                 strncpy(Dev->controller_name, current_controller_name, sizeof(Dev->controller_name));
  401.                 Dev->controller = current_controller;
  402.                 Dev->unit = dev_result->target_id;
  403.                 Dev->lun = dev_result->target_lun;
  404.                 break;
  405.             }
  406.             case DEV_MATCH_PERIPH:
  407.             {
  408.                 struct periph_match_result* periph_result;
  409.                 
  410.                 periph_result = &ccb.cdm.matches[i].result.periph_result;
  411.                 
  412.                 if(skip_device != 0) break;
  413.                 
  414.                 if(need_close==1) {
  415.                     snprintf(Dev->device, sizeof(Dev->device), "%s%d*",
  416.                         periph_result->periph_name,
  417.                         periph_result->unit_number);
  418.                     need_close = 0;
  419.                 }
  420.                 else if(need_close==0) {
  421.                     snprintf(Dev->pass_device, sizeof(Dev->pass_device), "%s%d",
  422.                         periph_result->periph_name,
  423.                         periph_result->unit_number);
  424.                     need_close++;
  425.                     break;
  426.                 }
  427.                 else {
  428.                     need_close = 0;
  429.                 }
  430.                 PrevDev = Dev;
  431.                 Dev = _AllocNewDevice();
  432.                 break;
  433.             }
  434.             }
  435.         }
  436.     } while (ccb.ccb_h.status == CAM_REQ_CMP
  437.          && ccb.cdm.status == CAM_DEV_MATCH_MORE);
  438.  
  439.     /* Remove last one (ugly coding) */
  440.     Devices = PrevDev;
  441.     delete Dev;
  442. end_loop:
  443.     close(fd);
  444. #else /* !CAM */
  445.     /*
  446.      * FreeBSD 2.x SCSI management is quiet different and 
  447.      * unfortunatly not flexible as CAM library in FreeBSD 3.x...
  448.      * I probe only the first bus, LUN 0, and the 
  449.      * first 8 devices only.
  450.      */
  451.     u_char* inq_buf;
  452.     scsireq_t* scsireq;
  453.     struct scsi_addr scsi;
  454.     int ssc_fd;
  455.     
  456.     if((ssc_fd=open("/dev/ssc", O_RDWR))==-1) {
  457.         fprintf(stderr, "Cannot open SCSI manager: /dev/ssc\n");
  458.         SCSIReset();
  459.         return;
  460.     }    
  461.     
  462.     inq_buf = (u_char*)malloc(96);
  463.     if(inq_buf==NULL) {
  464.         perror("malloc failed");
  465.         SCSIReset();
  466.         return;
  467.     }
  468.     
  469.     scsireq = scsireq_build((scsireq_t*)dev->dev_ptr,
  470.                 96, inq_buf, SCCMD_READ,
  471.                 "12 0 0 0 v 0", 96);
  472.     
  473.     addr.scbus = 0;
  474.     addr.lun = 0;
  475.  
  476.     for(int n=0;n<8;n++) {
  477.         addr.target = n;
  478.         
  479.         if(ioctl(ssc_fd, SCIOCADDR, &addr) != -1) {
  480.             Dev = _AllocNewDevice();
  481.             Dev->controller = addr.scbus;
  482.             Dev->lun = addr.lun;
  483.             Dev->unit = addr.target;
  484.  
  485.             struct scsi_devinfo devInfo;
  486.             devInfo.addr = addr;
  487.             if(ioctl(ssc_fd, SCIOCGETDEVINFO, &devInfo) != -1) {
  488.                 strncpy(Dev->device, devInfo.devname, sizeof(Dev->device));
  489.             }
  490.             strncpy(Dev->controller_name, "FreeBSD 2.x SCSI Manager", sizeof(Dev->controller_name));
  491.             if(scsireq_enter(ssc_fd, scsireq)!=-1) {
  492.                 Dev->vendor[sizeof(Dev->vendor)-1] = 0;
  493.                 Dev->product[sizeof(Dev->product)-1] = 0;
  494.                 Dev->revision[sizeof(Dev->revision)-1] = 0;
  495.                 
  496.                 scsireq_decode(scsireq, "s8 c8 c16 c4",
  497.                     Dev->vendor, Dev->product, Dev->revision);
  498.             }            
  499.         }
  500.     }
  501.     free(inq_buf);
  502.     close(ssc_fd);
  503. #endif /* !CAM */
  504.     _Build_SCSI_Controller();
  505.  
  506.     // Print out the periph with ID:LUNs
  507.     fprintf(stderr, "Device                            RealID FkdID  MacID Enabled\n");
  508.     fprintf(stderr, "-------------------------------------------------------------\n");
  509.               // 012345678901234567890123456789012 0:0:0    0/0    0:0 Yes
  510.     dev = Devices;
  511.     while(dev) {
  512.         char tmp[40];
  513.         snprintf(tmp, sizeof(tmp), "%s %s %s",
  514.             dev->vendor,
  515.             dev->product,
  516.             dev->revision);
  517.         fprintf(stderr, "%-33s %d:%d:%d    %d/%d    %d:%d %s\n",
  518.             tmp, dev->controller, dev->unit, dev->lun,
  519.             dev->faked_unit, dev->lun,
  520.             dev->mac_unit, dev->lun, dev->enabled?"Yes":"No");
  521.         dev = dev->next;
  522.     }
  523.  
  524. no_scsi:
  525.     // Reset SCSI bus
  526.     SCSIReset();
  527. }
  528.  
  529.  
  530. /*
  531.  *  Deinitialization
  532.  */
  533.  
  534. void SCSIExit(void)
  535. {
  536.     SCSIDevice* aux;
  537.     while(Devices) {
  538.         aux = Devices->next;
  539.         if(Devices->dev_ptr!=NULL) {
  540. #ifdef CAM
  541.             cam_close_device((struct cam_device*)Devices->dev_ptr);
  542. #else /* !CAM */
  543.             free(Devices->dev_ptr); // Is this right?
  544.             close(Devices->dev_fd); // And this one?
  545. #endif /* !CAM */
  546.         }
  547.         delete Devices;
  548.         Devices = aux;
  549.     }
  550.     nDevices = 0;
  551. }
  552.  
  553.  
  554. /*
  555.  *  Set SCSI command to be sent by scsi_send_cmd()
  556.  */
  557.  
  558. void scsi_set_cmd(int cmd_length, uint8 *cmd)
  559. {
  560.     the_cmd_len = cmd_length;
  561.     memset(the_cmd, 0, sizeof(the_cmd));
  562.     memcpy(the_cmd, cmd, the_cmd_len);
  563. }
  564.  
  565.  
  566. /*
  567.  *  Check for presence of SCSI target
  568.  */
  569.  
  570. bool scsi_is_target_present(int id)
  571. {
  572.     return (_GetSCSIDeviceByMacID(id)!=NULL&&_GetSCSIDeviceByMacID(id)->enabled);
  573. }
  574.  
  575.  
  576. /*
  577.  *  Set SCSI target (returns false on error)
  578.  */
  579.  
  580. bool scsi_set_target(int id, int lun)
  581. {
  582.     SCSIDevice* dev;
  583.  
  584.     dev = _GetSCSIDeviceByMacIDLUN(id, lun);
  585.     if(dev==NULL) return false;
  586.     CurrentDevice = dev;
  587.     return true;
  588. }
  589.  
  590.  
  591. /*
  592.  *  Send SCSI command to active target (scsi_set_command() must have been called),
  593.  *  read/write data according to S/G table (returns false on error)
  594.  */
  595.  
  596. static bool try_buffer(int size)
  597. {
  598.     if(size <= buffer_size) {
  599.         return true;
  600.     }
  601.     
  602.     D(bug("Allocating buffer of %d bytes.\n", size));
  603.     uint8* new_buffer = (uint8*)valloc(size);
  604.     if(new_buffer==NULL) {
  605.         return false;
  606.     }
  607.     if(buffer!=NULL) free(buffer);
  608.     buffer = new_buffer;
  609.     buffer_size = size;
  610.     return true;
  611. }
  612.  
  613. bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
  614. {
  615.     int value = 0;
  616. #ifdef CAM
  617. #ifdef VERBOSE_CAM_DEBUG
  618.     D(bug("Sending command %x (len=%d) to SCSI Device %d:%d:%d\n", the_cmd[0],
  619.         the_cmd_len,
  620.         CurrentDevice->controller,
  621.         CurrentDevice->unit,
  622.         CurrentDevice->lun));
  623.     D(bug("DataLength: %d\n", data_length));
  624.     D(bug("Reading: %d\n", reading));
  625.     D(bug("SG Size: %d\n", sg_size));
  626.     D(bug("Timeout: %d\n", timeout));
  627. #endif /* VERBOSE_CAM_DEBUG */
  628. #endif /* CAM */
  629.     if(!try_buffer(data_length)) {
  630.         char str[256];
  631.         sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
  632.         ErrorAlert(str);
  633.         return false;
  634.     }
  635.     
  636.     if(!reading) {
  637.         uint8* buffer_ptr = buffer;
  638.         for(int i=0;i<sg_size;i++) {
  639.             uint32 len = sg_len[i];
  640.             memcpy(buffer, sg_ptr[i], len);
  641.             buffer_ptr += len;
  642.         }
  643.     }
  644.     
  645.     if(the_cmd[0] == 0x03) {
  646.         // faked cmd
  647.         *stat = 0;
  648.         return true;
  649.     }
  650.  
  651.  
  652. #ifdef CAM
  653.     struct cam_device* device = _GetCurrentSCSIDevice();
  654.     if(device==NULL) return false;
  655.  
  656.     union ccb ccb;
  657.  
  658.     memset(&ccb, 0, sizeof(ccb));
  659.  
  660.     int dir_flags = CAM_DIR_NONE;
  661.     if(data_length>0) {
  662.         dir_flags = reading?CAM_DIR_IN:CAM_DIR_OUT;
  663.     }
  664.  
  665.     ccb.ccb_h.path_id = CurrentDevice->controller;
  666.     ccb.ccb_h.target_id = CurrentDevice->unit;
  667.     ccb.ccb_h.target_lun = CurrentDevice->lun;
  668.     
  669.     cam_fill_csio(&ccb.csio,
  670.             0,
  671.             NULL,
  672.             dir_flags,
  673.             MSG_SIMPLE_Q_TAG,
  674.             (u_int8_t*)buffer,
  675.             data_length,
  676.             SSD_FULL_SIZE,
  677.             the_cmd_len,
  678.             (timeout?timeout:50)*1000);
  679.  
  680.     ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
  681.  
  682.     memcpy(ccb.csio.cdb_io.cdb_bytes, the_cmd, the_cmd_len);
  683.  
  684.     if(cam_send_ccb(device, &ccb)<0) {
  685.         fprintf(stderr, "%d:%d:%d ", CurrentDevice->controller,
  686.             CurrentDevice->unit, CurrentDevice->lun);
  687.         perror("cam_send_ccb");
  688.         return false;
  689.     }
  690.  
  691.     value = ccb.ccb_h.status;
  692.     *stat = ccb.csio.scsi_status;
  693.  
  694.     if((value & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  695.         char tmp[4096];
  696.         if((value & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) {            
  697.             scsi_sense_string(device, &ccb.csio, tmp, sizeof(tmp));
  698.             fprintf(stderr, "SCSI Status Error:\n%s\n", tmp);
  699.             return false;
  700.         }
  701.     }
  702. #else /* !CAM */
  703.     struct scsireq* scsireq = _GetCurrentSCSIDevice();
  704.     if(device==NULL) return false;
  705.     
  706.     int dir_flags = 0x00;
  707.     if(data_length>0) dir_flags = reading?SCCMD_READ:SCCMD_WRITE;
  708.     
  709.     scsireq_reset(scsireq);
  710.     scsireq->timeout = (timeout?timeout:50)*1000;
  711.     scsireq_build(scsireq, data_length,
  712.             (caddr_t)buffer, dir_flags,
  713.             "0");
  714.     memcpy(scsireq->cmd, the_cmd, scsireq->cmdlen = the_cmd_len);
  715.     
  716.     int result = scsi_enter(dev->dev_fd, scsireq);
  717.     if(SCSIREQ_ERROR(result)) {
  718.         scsi_debug(stderr, result, scsireq);
  719.     }
  720.     *stat = scsireq->status;
  721. #endif /* !CAM */
  722.  
  723.     if(reading) {
  724.         uint8* buffer_ptr = buffer;
  725.         for(int i=0;i<sg_size;i++) {
  726.             uint32 len = sg_len[i];
  727.             memcpy(sg_ptr[i], buffer_ptr, len);
  728. #ifdef CAM
  729. #ifdef VERBOSE_CAM_DEBUG
  730.             static char line[16];
  731.             for(int r=0, x=0;x<len;x++) {
  732.                 if(x!=0&&x%16==0) { D(bug("%s\n", line)); r = 0; } 
  733.                 line[r++] = isprint(sg_ptr[i][x])?sg_ptr[i][x]:'.';
  734.                 line[r] = 0;
  735.                 D(bug("%02x ", sg_ptr[i][x]));
  736.             }
  737. #endif /* VERBOSE_CAM_DEBUG */
  738. #endif /* CAM */
  739.             buffer_ptr += len;
  740.         }
  741.     }
  742.     return true;
  743. }
  744.