home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / FreeBSD / scsidump.cpp < prev   
C/C++ Source or Header  |  1999-10-03  |  12KB  |  479 lines

  1. /*
  2.  *  scsidump.cpp - SCSI Dump (to see FreeBSD remappings)
  3.  *  Compile as (CAM version): gcc -I/sys -DCAM -o scsidump scsidump.cpp -lcam
  4.  *        (old SCSI version): gcc -o scsidump scsidump.cpp -lscsi
  5.  *  Copyright (C) 1999 Orlando Bassotto
  6.  *
  7.  *  Basilisk II (C) 1997-1999 Christian Bauer
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22.  *
  23.  *  History:
  24.  *    29-Jun-1999 Started
  25.  *    05-Jul-1999 Changed from array to queue removing the limit of 8 
  26.  *                devices.
  27.  *                Implemented old SCSI manager for FreeBSD 2.x.
  28.  *                (Note: This implementation have been never tested;
  29.  *                 I don't own anymore a machine with FreeBSD 2.x,
  30.  *                 so if something goes wrong, please mail me at
  31.  *                 future@mediabit.net).
  32.  */
  33.  
  34. #include <sys/ioctl.h>
  35. #include <sys/types.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <unistd.h>
  40. #include <fcntl.h>
  41. #include <ctype.h>
  42. #include <err.h>
  43.  
  44. #ifdef CAM
  45. #include <cam/cam.h>
  46. #include <cam/cam_debug.h>
  47. #include <cam/cam_ccb.h>
  48. #include <cam/scsi/scsi_all.h>
  49. #include <cam/scsi/scsi_da.h>
  50. #include <cam/scsi/scsi_pass.h>
  51. #include <cam/scsi/scsi_message.h>
  52. #include <camlib.h>
  53. #else /* !CAM */
  54. #include <sys/scsiio.h>
  55. #include <scsi.h>
  56. #endif /* !CAM */
  57.  
  58. #undef u_int8_t
  59. #define u_int8_t unsigned char
  60.  
  61. typedef struct _SCSIDevice {
  62.     int        controller;        // SCSI Controller
  63.     int        controller_bus;        // SCSI Controller Bus
  64.     char        controller_name[33];    // SCSI Controller name
  65.      int        mac_unit;        // Macintosh SCSI ID (remapped)
  66.     int        faked_controller;    // "Faked" SCSI Controller (Always 0)
  67.     int        faked_unit;        // "Faked" SCSI ID
  68.     int        unit;            // Real SCSI ID
  69.     int        lun;            // Real SCSI LUN
  70.     u_int8_t    vendor[16];        // SCSI Vendor
  71.     u_int8_t    product[48];        // SCSI Product
  72.     u_int8_t    revision[16];        // SCSI Revision
  73.     char        device[33];        // SCSI Device
  74. #ifdef CAM
  75.     char        pass_device[33];    // SCSI Pass Device
  76. #else /* !CAM */
  77.     int        dev_fd;            // Device File Descriptor
  78. #endif /* !CAM */
  79.     void*        dev_ptr;        // Pointer to CAM/SCSI structure
  80.     bool        enabled;        // Device enabled ?
  81.     struct _SCSIDevice* next;        // Pointer to the next device
  82. } SCSIDevice;
  83.  
  84. static int nDevices = 0;
  85. static SCSIDevice* Devices = NULL;
  86.  
  87. inline static SCSIDevice* _GetSCSIDeviceByID(int id)
  88. {
  89.     SCSIDevice* aux = Devices;
  90.     while(aux) {
  91.         if(aux->faked_unit==id) {
  92.             return aux;
  93.         }
  94.         aux = aux->next;
  95.     }
  96.     return NULL;
  97. }
  98.  
  99. inline static SCSIDevice* _GetSCSIDeviceByIDLUN(int id, int lun)
  100. {
  101.     SCSIDevice* aux = Devices;
  102.     while(aux) {
  103.         if(aux->faked_unit==id&&aux->lun==lun) {
  104.             return aux;
  105.         }
  106.         aux = aux->next;
  107.     }
  108.     return NULL;
  109. }
  110.  
  111. inline static SCSIDevice* _GetSCSIDeviceByMacID(int id)
  112. {
  113.     SCSIDevice* aux = Devices;
  114.     while(aux) {
  115.         if(aux->mac_unit==id) {
  116.             return aux;
  117.         }
  118.         aux = aux->next;
  119.     }
  120.     return NULL;
  121. }
  122.  
  123. inline static SCSIDevice* _GetSCSIDeviceByMacIDLUN(int id, int lun)
  124. {
  125.     SCSIDevice* aux = Devices;
  126.     while(aux) {
  127.         if(aux->mac_unit==id&&aux->lun==lun) {
  128.             return aux;
  129.         }
  130.         aux = aux->next;
  131.     }
  132.     return NULL;
  133. }
  134.  
  135. inline static SCSIDevice* _AllocNewDevice()
  136. {
  137.     SCSIDevice* aux;
  138.     
  139.     aux = new SCSIDevice;
  140.     if(aux==NULL) return NULL;
  141.     memset(aux, 0, sizeof(SCSIDevice));
  142.     aux->next = Devices;
  143.     Devices = aux;
  144.     return aux;
  145. }
  146.  
  147. /*
  148.  * _Build_SCSI_Controller()
  149.  *
  150.  * This function builds a virtual SCSI Controller (Controller=0)
  151.  * where keeps all the devices found, this is due the fact
  152.  * I have two SCSI controllers in my PC. :-)
  153.  * Use FreeBSD-SCSIDump in contrib/ to see how is remapped your 
  154.  * SCSI device (only if you have more than one controller, 
  155.  * that's for sure :-).
  156.  */
  157.  
  158. #define GET_FREE_ID(id) \
  159.     { \
  160.         for(int x=0;x<32;x++) { \
  161.             if(!(busyIDs&(1<<(x+1)))) { \
  162.                 id = x; \
  163.                 break; \
  164.             } \
  165.         } \
  166.     }
  167.     
  168. static void _Build_SCSI_Controller()
  169. {
  170.     unsigned int id = 0;
  171.     unsigned long long busyIDs = 0x0ll;
  172.     SCSIDevice* aux, * dev;
  173.         
  174.     // What IDs are busy?
  175.     dev = Devices;
  176.     while(dev) {
  177.         dev->enabled = false;
  178.         dev->faked_controller = 0;
  179.         dev->faked_unit = dev->unit;
  180.         busyIDs |= (1 << (dev->unit+1));
  181.         dev = dev->next;
  182.     }
  183.     
  184.     // Find out the duplicate IDs and change them
  185.     dev = Devices, aux = NULL;
  186.     while(dev) {
  187.         aux = dev;
  188.         while(aux) {
  189.             SCSIDevice* dev1, * dev2;
  190.             
  191.             dev1 = dev, dev2 = aux;
  192.             
  193.             if(dev1->controller!=dev2->controller&&
  194.                 dev1->unit==dev2->unit) {
  195.                 int free_id;
  196.                 GET_FREE_ID(free_id);
  197.                 busyIDs |= (1<<(free_id+1));
  198.                 dev1->faked_unit = free_id;
  199.             }
  200.             aux = aux->next;
  201.         }
  202.         dev = dev->next;
  203.     }
  204.     
  205.     // Now reorder the queue 
  206.     dev = Devices;
  207.     while(dev) {
  208.         aux = dev;
  209.         while(aux) {
  210.             SCSIDevice* dev1, * dev2;
  211.     
  212.             dev1 = dev, dev2 = aux;
  213. /*            
  214.             if(dev1->faked_unit>dev2->faked_unit) {
  215.                 SCSIDevice tmp;
  216.                 
  217.                 memcpy(&tmp, dev1, sizeof(SCSIDevice));
  218.                 memcpy(dev1, dev2, sizeof(SCSIDevice));
  219.                 memcpy(dev2, &tmp, sizeof(SCSIDevice));
  220.             }
  221.             */
  222.             aux = aux->next;
  223.         }
  224.         dev = dev->next;
  225.     }
  226. }    
  227.  
  228. #define SCSIReset()
  229.     
  230. /*
  231.  *  Initialization
  232.  */
  233.  
  234. void SCSIInit(void)
  235. {
  236.     // Find the SCSI hosts in the system
  237.     // Filling out the SCSIDevices queue.
  238.     // Stolen from camcontrol.c
  239.     int bufsize, fd;
  240.     int need_close = 0;
  241.     int error = 0;
  242.     int skip_device = 0;
  243.     SCSIDevice* Dev, * dev, * PrevDev = NULL;
  244.     
  245.     nDevices = 0;
  246.  
  247. #ifdef CAM
  248.     union ccb ccb;
  249.  
  250.     if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
  251.         fprintf(stderr, "Cannot open CAM device: %s\n", XPT_DEVICE);
  252.         goto no_scsi;
  253.     }
  254.     
  255.     memset(&(&ccb.ccb_h)[1], 0, sizeof(struct ccb_dev_match)-sizeof(struct ccb_hdr));
  256.     ccb.ccb_h.func_code = XPT_DEV_MATCH;
  257.     bufsize = sizeof(struct dev_match_result) * 100;
  258.     ccb.cdm.match_buf_len = bufsize;
  259.     ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
  260.     ccb.cdm.num_matches = 0;
  261.     
  262.     ccb.cdm.num_patterns = 0;
  263.     ccb.cdm.pattern_buf_len = 0;
  264.     
  265.     do {
  266.         Dev = _AllocNewDevice();    
  267.         if(ioctl(fd, CAMIOCOMMAND, &ccb)==-1) {
  268.             fprintf(stderr, "Error sending CAMIOCOMMAND ioctl\n");
  269.             return;
  270.         }
  271.         
  272.         if((ccb.ccb_h.status != CAM_REQ_CMP)
  273.         || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
  274.          && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
  275.              fprintf(stderr, "Got CAM error %#x, CDM error %d\n",
  276.                  ccb.ccb_h.status, ccb.cdm.status);
  277.              return;
  278.         }
  279.          
  280.         char current_controller_name[33];
  281.         int current_controller = -1;
  282.         for(int i=0;i<ccb.cdm.num_matches;i++) {
  283.             switch(ccb.cdm.matches[i].type) {
  284.             case DEV_MATCH_BUS:
  285.             {
  286.                 struct bus_match_result* bus_result;
  287.                                 
  288.                 bus_result = &ccb.cdm.matches[i].result.bus_result;
  289.                 
  290.                 if(bus_result->path_id==-1) break;
  291.                 Dev->controller = bus_result->path_id;
  292.                 snprintf(Dev->controller_name, sizeof(Dev->controller_name), "%s%d", 
  293.                     bus_result->dev_name,
  294.                     bus_result->unit_number);
  295.                 strncpy(current_controller_name, Dev->controller_name, sizeof(current_controller_name));
  296.                 current_controller = Dev->controller;
  297.                 Dev->controller_bus = bus_result->bus_id;
  298.                 break;
  299.             }
  300.             case DEV_MATCH_DEVICE:
  301.             {
  302.                 struct device_match_result* dev_result;
  303.                 char tmpstr[256];
  304.                 
  305.                 dev_result = &ccb.cdm.matches[i].result.device_result;
  306.                 if(current_controller==-1||dev_result->target_id==-1) {
  307.                     skip_device = 1;
  308.                     break;
  309.                 }
  310.                 else skip_device = 0;
  311.                 
  312.                 cam_strvis(Dev->vendor, (u_int8_t*)dev_result->inq_data.vendor,
  313.                     sizeof(dev_result->inq_data.vendor),
  314.                     sizeof(Dev->vendor));
  315.                 cam_strvis(Dev->product, (u_int8_t*)dev_result->inq_data.product,
  316.                     sizeof(dev_result->inq_data.product),
  317.                     sizeof(Dev->product));
  318.                 cam_strvis(Dev->revision, (u_int8_t*)dev_result->inq_data.revision,
  319.                     sizeof(dev_result->inq_data.revision),
  320.                     sizeof(Dev->revision));
  321.                 strncpy(Dev->controller_name, current_controller_name, sizeof(Dev->controller_name));
  322.                 Dev->controller = current_controller;
  323.                 Dev->unit = dev_result->target_id;
  324.                 Dev->lun = dev_result->target_lun;
  325.                 break;
  326.             }
  327.             case DEV_MATCH_PERIPH:
  328.             {
  329.                 struct periph_match_result* periph_result;
  330.                 
  331.                 periph_result = &ccb.cdm.matches[i].result.periph_result;
  332.                 
  333.                 if(skip_device != 0) break;
  334.                 
  335.                 if(need_close==1) {
  336.                     snprintf(Dev->device, sizeof(Dev->device), "%s%d*",
  337.                         periph_result->periph_name,
  338.                         periph_result->unit_number);
  339.                     need_close = 0;
  340.                 }
  341.                 else if(need_close==0) {
  342.                     snprintf(Dev->pass_device, sizeof(Dev->pass_device), "%s%d",
  343.                         periph_result->periph_name,
  344.                         periph_result->unit_number);
  345.                     need_close++;
  346.                     break;
  347.                 }
  348.                 else {
  349.                     need_close = 0;
  350.                 }
  351.                 PrevDev = Dev;
  352.                 Dev = _AllocNewDevice();
  353.                 break;
  354.             }
  355.             }
  356.         }
  357.     } while (ccb.ccb_h.status == CAM_REQ_CMP
  358.          && ccb.cdm.status == CAM_DEV_MATCH_MORE);
  359.  
  360.     /* Remove last one (ugly coding) */
  361.     Devices = PrevDev;
  362.     delete Dev;
  363. end_loop:
  364.     close(fd);
  365. #else /* !CAM */
  366.     /*
  367.      * FreeBSD 2.x SCSI management is quiet different and 
  368.      * unfortunatly not flexible as CAM library in FreeBSD 3.x...
  369.      * I only scan for the first bus, LUN 0, and the 
  370.      * first 8 devices only.
  371.      */
  372.     u_char* inq_buf;
  373.     scsireq_t* scsireq;
  374.     struct scsi_addr scsi;
  375.     int ssc_fd;
  376.     
  377.     if((ssc_fd=open("/dev/ssc", O_RDWR))==-1) {
  378.         fprintf(stderr, "Cannot open SCSI manager: /dev/ssc\n");
  379.         SCSIReset();
  380.         return;
  381.     }    
  382.     
  383.     inq_buf = (u_char*)malloc(96);
  384.     if(inq_buf==NULL) {
  385.         perror("malloc failed");
  386.         SCSIReset();
  387.         return;
  388.     }
  389.     
  390.     scsireq = scsireq_build((scsireq_t*)dev->dev_ptr,
  391.                 96, inq_buf, SCCMD_READ,
  392.                 "12 0 0 0 v 0", 96);
  393.     
  394.     addr.scbus = 0;
  395.     addr.lun = 0;
  396.  
  397.     for(int n=0;n<8;n++) {
  398.         addr.target = n;
  399.         
  400.         if(ioctl(ssc_fd, SCIOCADDR, &addr) != -1) {
  401.             Dev = _AllocNewDevice();
  402.             Dev->controller = addr.scbus;
  403.             Dev->lun = addr.lun;
  404.             Dev->unit = addr.target;
  405.  
  406.             struct scsi_devinfo devInfo;
  407.             devInfo.addr = addr;
  408.             if(ioctl(ssc_fd, SCIOCGETDEVINFO, &devInfo) != -1) {
  409.                 strncpy(Dev->device, devInfo.devname, sizeof(Dev->device));
  410.             }
  411.             strncpy(Dev->controller_name, "FreeBSD 2.x SCSI Manager", sizeof(Dev->controller_name));
  412.             if(scsireq_enter(ssc_fd, scsireq)!=-1) {
  413.                 Dev->vendor[sizeof(Dev->vendor)-1] = 0;
  414.                 Dev->product[sizeof(Dev->product)-1] = 0;
  415.                 Dev->revision[sizeof(Dev->revision)-1] = 0;
  416.                 
  417.                 scsireq_decode(scsireq, "s8 c8 c16 c4",
  418.                     Dev->vendor, Dev->product, Dev->revision);
  419.             }            
  420.         }
  421.     }
  422.     free(inq_buf);
  423.     close(ssc_fd);
  424. #endif /* !CAM */
  425.     _Build_SCSI_Controller();
  426.  
  427.     // Print out the periph with ID:LUNs
  428.     fprintf(stderr, "Device                            RealID FkdID\n");
  429.     fprintf(stderr, "----------------------------------------------\n");
  430.               // 012345678901234567890123456789012 0:0:0    0/0
  431.     dev = Devices;
  432.     while(dev) {
  433.         char tmp[40];
  434.         snprintf(tmp, sizeof(tmp), "%s %s %s",
  435.             dev->vendor,
  436.             dev->product,
  437.             dev->revision);
  438.         fprintf(stderr, "%-33s %d:%d:%d    %d/%d\n",
  439.             tmp, dev->controller, dev->unit, dev->lun,
  440.             dev->faked_unit, dev->lun);
  441.         dev = dev->next;
  442.     }
  443.  
  444. no_scsi:
  445.     // Reset SCSI bus
  446.     SCSIReset();
  447. }
  448.  
  449.  
  450. /*
  451.  *  Deinitialization
  452.  */
  453.  
  454. void SCSIExit(void)
  455. {
  456.     SCSIDevice* aux;
  457.     while(Devices) {
  458.         aux = Devices->next;
  459.         if(Devices->dev_ptr!=NULL) {
  460. #ifdef CAM
  461.             cam_close_device((struct cam_device*)Devices->dev_ptr);
  462. #else /* !CAM */
  463.             free(Devices->dev_ptr); // Is this right?
  464.             close(Devices->dev_fd); // And this one?
  465. #endif /* !CAM */
  466.         }
  467.         delete Devices;
  468.         Devices = aux;
  469.     }
  470.     nDevices = 0;
  471. }
  472.  
  473. int main()
  474. {
  475.     SCSIInit();
  476.     SCSIExit();
  477.     return 0;
  478. }
  479.