Back to index

lshw  02.16
ideraid.cc
Go to the documentation of this file.
00001 /*
00002  *  ideraid.cc
00003  *
00004  */
00005 
00006 #include "version.h"
00007 #include "cpuinfo.h"
00008 #include "osutils.h"
00009 #include "cdrom.h"
00010 #include "disk.h"
00011 #include "heuristics.h"
00012 #include <sys/types.h>
00013 #include <sys/ioctl.h>
00014 #include <sys/stat.h>
00015 #include <endian.h>
00016 #include <stdint.h>
00017 #include <fcntl.h>
00018 #include <unistd.h>
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <dirent.h>
00022 #include <ctype.h>
00023 #include <vector>
00024 #include <linux/hdreg.h>
00025 #include <regex.h>
00026 
00027 __ID("@(#) $Id: ideraid.cc 2433 2012-01-10 22:01:30Z lyonel $");
00028 
00029 #define DEV_TWE "/dev/twe"
00030 
00031 #define IORDY_SUP               0x0800            /* 1=support; 0=may be supported */
00032 #define IORDY_OFF               0x0400            /* 1=may be disabled */
00033 #define LBA_SUP                 0x0200            /* 1=Logical Block Address support */
00034 #define DMA_SUP                 0x0100            /* 1=Direct Memory Access support */
00035 #define DMA_IL_SUP              0x8000            /* 1=interleaved DMA support (ATAPI) */
00036 #define CMD_Q_SUP               0x4000            /* 1=command queuing support (ATAPI) */
00037 #define OVLP_SUP                0x2000            /* 1=overlap operation support (ATAPI) */
00038 
00039 #define GEN_CONFIG              0                 /* general configuration */
00040 #define CD_ROM                  5
00041 #define NOT_ATA                 0x8000
00042 #define NOT_ATAPI               0x4000            /* (check only if bit 15 == 1) */
00043 #define EQPT_TYPE               0x1f00
00044 
00045 static const char *description[] =
00046 {
00047   "Direct-access device",                         /* word 0, bits 12-8 = 00 */
00048   "Sequential-access device",                     /* word 0, bits 12-8 = 01 */
00049   "Printer",                                      /* word 0, bits 12-8 = 02 */
00050   "Processor",                                    /* word 0, bits 12-8 = 03 */
00051   "Write-once device",                            /* word 0, bits 12-8 = 04 */
00052   "CD-ROM",                                       /* word 0, bits 12-8 = 05 */
00053   "Scanner",                                      /* word 0, bits 12-8 = 06 */
00054   "Optical memory",                               /* word 0, bits 12-8 = 07 */
00055   "Medium changer",                               /* word 0, bits 12-8 = 08 */
00056   "Communications device",                        /* word 0, bits 12-8 = 09 */
00057   "ACS-IT8 device",                               /* word 0, bits 12-8 = 0a */
00058   "ACS-IT8 device",                               /* word 0, bits 12-8 = 0b */
00059   "Array controller",                             /* word 0, bits 12-8 = 0c */
00060   "Enclosure services",                           /* word 0, bits 12-8 = 0d */
00061   "Reduced block command device",                 /* word 0, bits 12-8 = 0e */
00062   "Optical card reader/writer",                   /* word 0, bits 12-8 = 0f */
00063   "",                                             /* word 0, bits 12-8 = 10 */
00064   "",                                             /* word 0, bits 12-8 = 11 */
00065   "",                                             /* word 0, bits 12-8 = 12 */
00066   "",                                             /* word 0, bits 12-8 = 13 */
00067   "",                                             /* word 0, bits 12-8 = 14 */
00068   "",                                             /* word 0, bits 12-8 = 15 */
00069   "",                                             /* word 0, bits 12-8 = 16 */
00070   "",                                             /* word 0, bits 12-8 = 17 */
00071   "",                                             /* word 0, bits 12-8 = 18 */
00072   "",                                             /* word 0, bits 12-8 = 19 */
00073   "",                                             /* word 0, bits 12-8 = 1a */
00074   "",                                             /* word 0, bits 12-8 = 1b */
00075   "",                                             /* word 0, bits 12-8 = 1c */
00076   "",                                             /* word 0, bits 12-8 = 1d */
00077   "",                                             /* word 0, bits 12-8 = 1e */
00078   "Unknown",                                      /* word 0, bits 12-8 = 1f */
00079 };
00080 
00081 /* older kernels (2.2.x) have incomplete id structure for IDE devices */
00082 #ifndef __NEW_HD_DRIVE_ID
00083 #define command_set_1 command_sets
00084 #define command_set_2 word83
00085 #define hw_config word93
00086 #endif
00087 
00088 
00089 #define ATA_SMART_CMD                   0xb0
00090 #define ATA_IDENTIFY_DEVICE             0xec
00091 
00092 #define TW_OP_ATA_PASSTHRU 0x11
00093 
00094 #define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108
00095 #define TW_CMD_PACKET_WITH_DATA 0x1f
00096 
00097 #define TW_MAX_SGL_LENGTH   62
00098 
00099 typedef struct TAG_TW_Ioctl {
00100   int input_length;
00101   int output_length;
00102   unsigned char cdb[16];
00103   unsigned char opcode;
00104   // This one byte of padding is missing from the typedefs in the
00105   // kernel code, but it is indeed present.  We put it explicitly
00106   // here, so that the structure can be packed.  Adam agrees with
00107   // this.
00108   unsigned char packing;
00109   unsigned short table_id;
00110   unsigned char parameter_id;
00111   unsigned char parameter_size_bytes;
00112   unsigned char unit_index;
00113   // Size up to here is 30 bytes + 1 padding!
00114   unsigned char input_data[499];
00115   // Reserve lots of extra space for commands that set Sector Count
00116   // register to large values
00117   unsigned char output_data[512]; // starts 530 bytes in!
00118   // two more padding bytes here if structure NOT packed.
00119 } TW_Ioctl;
00120 
00121 
00122 /* 512 is the max payload size: increase if needed */
00123 #define TW_IOCTL_BUFFER_SIZE sizeof(TW_Ioctl)
00124 
00125 #pragma pack(1)
00126 /* Scatter gather list entry */
00127 typedef struct TAG_TW_SG_Entry {
00128   unsigned int address;
00129   unsigned int length;
00130 } TW_SG_Entry;
00131 
00132 /* Command header for ATA pass-thru.  Note that for different
00133    drivers/interfaces the length of sg_list (here TW_ATA_PASS_SGL_MAX)
00134    is different.  But it can be taken as same for all three cases
00135    because it's never used to define any other structures, and we
00136    never use anything in the sg_list or beyond! */
00137 
00138 #define TW_ATA_PASS_SGL_MAX      60
00139 
00140 typedef struct TAG_TW_Passthru {
00141   struct {
00142     unsigned char opcode:5;
00143     unsigned char sgloff:3;
00144   } byte0;
00145   unsigned char size;
00146   unsigned char request_id;
00147   struct {
00148     unsigned char aport:4;
00149     unsigned char host_id:4;
00150   } byte3;
00151   unsigned char status;  // On return, contains 3ware STATUS register
00152   unsigned char flags;
00153   unsigned short param;
00154   unsigned short features;  // On return, contains ATA ERROR register
00155   unsigned short sector_count;
00156   unsigned short sector_num;
00157   unsigned short cylinder_lo;
00158   unsigned short cylinder_hi;
00159   unsigned char drive_head;
00160   unsigned char command; // On return, contains ATA STATUS register
00161   TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX];
00162   unsigned char padding[12];
00163 } TW_Passthru;
00164 
00165 /* Command Packet */
00166 typedef struct TW_Command {
00167   /* First DWORD */
00168   struct {
00169     unsigned char opcode:5;
00170     unsigned char sgl_offset:3;
00171   } byte0;
00172   unsigned char size;
00173   unsigned char request_id;
00174   struct {
00175     unsigned char unit:4;
00176     unsigned char host_id:4;
00177   } byte3;
00178   /* Second DWORD */
00179   unsigned char status;
00180   unsigned char flags;
00181   union {
00182     unsigned short block_count;
00183     unsigned short parameter_count;
00184     unsigned short message_credits;
00185   } byte6;
00186   union {
00187     struct {
00188       uint32_t lba;
00189       TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
00190       uint32_t padding;      /* pad to 512 bytes */
00191     } io;
00192     struct {
00193       TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
00194       uint32_t padding[2];
00195     } param;
00196     struct {
00197       uint32_t response_queue_pointer;
00198       uint32_t padding[125];
00199     } init_connection;
00200     struct {
00201       char version[504];
00202     } ioctl_miniport_version;
00203   } byte8;
00204 } TW_Command;
00205 
00206 typedef struct TAG_TW_New_Ioctl {
00207   unsigned int  data_buffer_length;
00208   unsigned char padding [508];
00209   TW_Command    firmware_command;
00210   unsigned char          data_buffer[1];
00211   // three bytes of padding here
00212 } TW_New_Ioctl;
00213 
00214 static void fix_string(unsigned char * s, unsigned len)
00215 {
00216   unsigned char c;
00217 
00218   while(len>1)
00219   {
00220     c = s[0];
00221     s[0] = s[1];
00222     s[1] = c;
00223     s += 2;
00224     len -= 2;
00225   }
00226 }
00227 
00228 static bool guess_manufacturer(hwNode & device);
00229 
00230 static bool probe_port(unsigned controller, unsigned disknum, hwNode & parent)
00231 {
00232   hwNode device("member:"+tostring(disknum), hw::disk);
00233   struct hd_driveid id;
00234   const u_int8_t *id_regs = (const u_int8_t *) &id;
00235   string devname = string(DEV_TWE) + tostring(controller);
00236   int fd = open(devname.c_str(), O_RDONLY | O_NONBLOCK);
00237   unsigned char ioctl_buffer[2*TW_IOCTL_BUFFER_SIZE];
00238 
00239    // only used for 6000/7000/8000 char device interface
00240   TW_New_Ioctl *tw_ioctl_char=NULL;
00241   TW_Passthru *passthru=NULL;
00242 
00243   memset(ioctl_buffer, 0, sizeof(ioctl_buffer));
00244 
00245   tw_ioctl_char = (TW_New_Ioctl *)ioctl_buffer;
00246   tw_ioctl_char->data_buffer_length = 512;
00247   passthru = (TW_Passthru *)&(tw_ioctl_char->firmware_command);
00248 
00249   passthru->byte0.opcode  = TW_OP_ATA_PASSTHRU;
00250   passthru->request_id    = 0xFF;
00251   passthru->byte3.aport   = disknum;
00252   passthru->byte3.host_id = 0;
00253   passthru->status        = 0;
00254   passthru->flags         = 0x1;
00255   passthru->drive_head    = 0x0;
00256   passthru->sector_num    = 0;
00257   passthru->byte0.sgloff = 0x5;
00258   passthru->size         = 0x7;
00259   passthru->param        = 0xD;
00260   passthru->sector_count = 0x1;
00261   passthru->command       = ATA_IDENTIFY_DEVICE;
00262   passthru->features    = 0;
00263   passthru->cylinder_lo = 0;
00264   passthru->cylinder_hi = 0;
00265 
00266   if (fd < 0)
00267     return false;
00268 
00269   memset(&id, 0, sizeof(id));
00270   if (ioctl(fd, TW_CMD_PACKET_WITH_DATA, tw_ioctl_char) != 0)
00271   {
00272     close(fd);
00273     return false;
00274   }
00275 
00276   close(fd);
00277 
00278   device.setPhysId(disknum);
00279   device.setBusInfo("raid@c" + tostring(controller) + "/p" + tostring(disknum));
00280   device.setLogicalName("c" + tostring(controller) + "/p" + tostring(disknum));
00281   device.claim();
00282 
00283   u_int16_t pidentity[256];
00284   for (int i = 0; i < 256; i++)
00285     pidentity[i] = tw_ioctl_char->data_buffer[2 * i] + (tw_ioctl_char->data_buffer[2 * i + 1] << 8);
00286   memcpy(&id, pidentity, sizeof(id));
00287 
00288   fix_string(id.model, sizeof(id.model));
00289   fix_string(id.fw_rev, sizeof(id.fw_rev));
00290   fix_string(id.serial_no, sizeof(id.serial_no));
00291 
00292   if (id.model[0])
00293     device.setProduct(hw::strip(string((char *) id.model, sizeof(id.model))));
00294   else
00295     return false;
00296   if (id.fw_rev[0])
00297     device.
00298       setVersion(hw::strip(string((char *) id.fw_rev, sizeof(id.fw_rev))));
00299   else
00300     return false;
00301   if (id.serial_no[0])
00302     device.
00303       setSerial(hw::
00304       strip(string((char *) id.serial_no, sizeof(id.serial_no))));
00305   else
00306     return false;
00307 
00308   if (!(pidentity[GEN_CONFIG] & NOT_ATA))
00309   {
00310     device.addCapability("ata", "ATA");
00311     device.setDescription("ATA Disk");
00312   }
00313   else if (!(pidentity[GEN_CONFIG] & NOT_ATAPI))
00314   {
00315     u_int8_t eqpt = (pidentity[GEN_CONFIG] & EQPT_TYPE) >> 8;
00316     device.addCapability("atapi", "ATAPI");
00317 
00318     if (eqpt == CD_ROM)
00319       device.addCapability("cdrom", "can read CD-ROMs");
00320 
00321     if (eqpt < 0x20)
00322       device.setDescription("IDE " + string(description[eqpt]));
00323   }
00324   if (id.config & (1 << 7))
00325     device.addCapability("removable", "support is removable");
00326   if (id.config & (1 << 15))
00327     device.addCapability("nonmagnetic", "support is non-magnetic (optical)");
00328   if (id.capability & 1)
00329     device.addCapability("dma", "Direct Memory Access");
00330   if (id.capability & 2)
00331     device.addCapability("lba", "Large Block Addressing");
00332   if (id.capability & 8)
00333     device.addCapability("iordy", "I/O ready reporting");
00334   if (id.command_set_1 & 1)
00335     device.addCapability("smart",
00336       "S.M.A.R.T. (Self-Monitoring And Reporting Technology)");
00337   if (id.command_set_1 & 2)
00338     device.addCapability("security", "ATA security extensions");
00339   if (id.command_set_1 & 4)
00340     device.addCapability("removable", "support is removable");
00341   if (id.command_set_1 & 8)
00342     device.addCapability("pm", "Power Management");
00343   if (id.command_set_2 & 8)
00344     device.addCapability("apm", "Advanced Power Management");
00345 
00346   if ((id.capability & 8) || (id.field_valid & 2))
00347   {
00348     if (id.field_valid & 4)
00349     {
00350       if (id.dma_ultra & 0x100)
00351         device.setConfig("mode", "udma0");
00352       if (id.dma_ultra & 0x200)
00353         device.setConfig("mode", "udma1");
00354       if (id.dma_ultra & 0x400)
00355         device.setConfig("mode", "udma2");
00356       if (id.hw_config & 0x2000)
00357       {
00358         if (id.dma_ultra & 0x800)
00359           device.setConfig("mode", "udma3");
00360         if (id.dma_ultra & 0x1000)
00361           device.setConfig("mode", "udma4");
00362         if (id.dma_ultra & 0x2000)
00363           device.setConfig("mode", "udma5");
00364         if (id.dma_ultra & 0x4000)
00365           device.setConfig("mode", "udma6");
00366         if (id.dma_ultra & 0x8000)
00367           device.setConfig("mode", "udma7");
00368       }
00369     }
00370   }
00371 
00372   if (id_regs[83] & 8)
00373     device.addCapability("apm", "Advanced Power Management");
00374 
00375 //if (device.isCapable("iordy") && (id.capability & 4))
00376 //device.setConfig("iordy", "yes");
00377 
00378   if (device.isCapable("smart"))
00379   {
00380     if (id.command_set_2 & (1 << 14))
00381       device.setConfig("smart", "on");
00382     else
00383       device.setConfig("smart", "off");
00384   }
00385 
00386   if (device.isCapable("apm"))
00387   {
00388     if (!(id_regs[86] & 8))
00389       device.setConfig("apm", "off");
00390     else
00391       device.setConfig("apm", "on");
00392   }
00393 
00394   if (device.isCapable("lba"))
00395     device.setCapacity((unsigned long long) id.lba_capacity * 512);
00396   if (device.isCapable("removable"))
00397     device.setCapacity(0);                        // we'll first have to make sure we have a disk
00398 
00399   if (device.isCapable("cdrom"))
00400     scan_cdrom(device);
00401   else
00402     scan_disk(device);
00403 
00404 #if 0
00405   if (!(iddata[GEN_CONFIG] & NOT_ATA))
00406     device.addCapability("ata");
00407   else if (iddata[GEN_CONFIG] == CFA_SUPPORT_VAL)
00408   {
00409     device.addCapability("ata");
00410     device.addCapability("compactflash");
00411   }
00412   else if (!(iddata[GEN_CONFIG] & NOT_ATAPI))
00413   {
00414     device.addCapability("atapi");
00415     device.setDescription(description[(iddata[GEN_CONFIG] & EQPT_TYPE) >> 8]);
00416   }
00417 
00418   if (iddata[START_MODEL])
00419     device.setProduct(print_ascii((char *) &iddata[START_MODEL],
00420       LENGTH_MODEL));
00421   if (iddata[START_SERIAL])
00422     device.
00423       setSerial(print_ascii((char *) &iddata[START_SERIAL], LENGTH_SERIAL));
00424   if (iddata[START_FW_REV])
00425     device.
00426       setVersion(print_ascii((char *) &iddata[START_FW_REV], LENGTH_FW_REV));
00427   if (iddata[CAPAB_0] & LBA_SUP)
00428     device.addCapability("lba");
00429   if (iddata[CAPAB_0] & IORDY_SUP)
00430     device.addCapability("iordy");
00431   if (iddata[CAPAB_0] & IORDY_OFF)
00432   {
00433     device.addCapability("iordy");
00434     device.addCapability("iordyoff");
00435   }
00436   if (iddata[CAPAB_0] & DMA_SUP)
00437     device.addCapability("dma");
00438   if (iddata[CAPAB_0] & DMA_IL_SUP)
00439   {
00440     device.addCapability("interleaved_dma");
00441     device.addCapability("dma");
00442   }
00443   if (iddata[CAPAB_0] & CMD_Q_SUP)
00444     device.addCapability("command_queuing");
00445   if (iddata[CAPAB_0] & OVLP_SUP)
00446     device.addCapability("overlap_operation");
00447 #endif
00448 
00449   guess_manufacturer(device);
00450   parent.addChild(device);
00451   return true;
00452 }
00453 
00454 
00455 static const char *manufacturers[] =
00456 {
00457   "^ST.+", "Seagate",
00458   "^D...-.+", "IBM",
00459   "^IBM.+", "IBM",
00460   "^HITACHI.+", "Hitachi",
00461   "^IC.+", "Hitachi",
00462   "^HTS.+", "Hitachi",
00463   "^FUJITSU.+", "Fujitsu",
00464   "^MP.+", "Fujitsu",
00465   "^TOSHIBA.+", "Toshiba",
00466   "^MK.+", "Toshiba",
00467   "^MAXTOR.+", "Maxtor",
00468   "^Pioneer.+", "Pioneer",
00469   "^PHILIPS.+", "Philips",
00470   "^QUANTUM.+", "Quantum",
00471   "FIREBALL.+", "Quantum",
00472   "^WDC.+", "Western Digital",
00473   "WD.+", "Western Digital",
00474   NULL, NULL
00475 };
00476 
00477 static bool guess_manufacturer(hwNode & device)
00478 {
00479   int i = 0;
00480   bool result = false;
00481 
00482   while (manufacturers[i])
00483   {
00484     if (matches(device.getProduct().c_str(), manufacturers[i], REG_ICASE))
00485     {
00486       device.setVendor(manufacturers[i + 1]);
00487       result = true;
00488     }
00489     i += 2;
00490   }
00491 
00492 
00493   return result;
00494 }
00495 
00496 
00497 bool scan_ideraid(hwNode & n)
00498 {
00499   unsigned c = 0;
00500   unsigned u = 0;
00501 
00502   for(c=0; c<16; c++)
00503   {
00504     for(u=0; u<8; u++)
00505       if(!probe_port(c,u,n))
00506         break;
00507   }
00508 
00509   return true;
00510 }