1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

Changeset 3650

Show
Ignore:
Timestamp:
10/18/12 14:26:56 (7 months ago)
Author:
samm2
Message:

FreeBSD: Migrate 3ware interface to ata_pass_through()

Location:
trunk/smartmontools
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/smartmontools/ChangeLog

    r3649 r3650  
    44        Compile fixes for Areca patch on FreeBSD. 
    55        Added support for the /dev/twsX (3ware 9750) controller on FreeBSD. 
     6        FreeBSD: Migrate 3ware interface to ata_pass_through() 
    67 
    782012-10-16  Christian Franke  <franke@computer.org> 
  • trunk/smartmontools/os_freebsd.cpp

    r3649 r3650  
    455455 
    456456class freebsd_escalade_device 
    457 : public /*implements*/ ata_device_with_command_set, 
     457: public /*implements*/ ata_device, 
    458458  public /*extends*/ freebsd_smart_device 
    459459{ 
     
    463463 
    464464protected: 
    465   virtual int ata_command_interface(smart_command_set command, int select, char * data); 
     465  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 
    466466  virtual bool open(); 
    467467 
     
    496496} 
    497497 
    498 int freebsd_escalade_device::ata_command_interface(smart_command_set command, int select, char * data) 
     498bool freebsd_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 
    499499{ 
    500500  // to hold true file descriptor 
    501501  int fd = get_fd(); 
    502502 
    503   // return value and buffer for ioctl() 
    504   int  ioctlreturn, readdata=0; 
     503  if (!ata_cmd_is_ok(in, 
     504    true, // data_out_support 
     505    false, // TODO: multi_sector_support 
     506    true) // ata_48bit_support 
     507  ) 
     508  return false; 
     509 
    505510  struct twe_usercommand* cmd_twe = NULL; 
    506511  TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL; 
     
    526531    ata = &cmd_twe->tu_command.ata; 
    527532  } else { 
    528     pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n" 
    529       "Please contact " PACKAGE_BUGREPORT "\n", m_escalade_type, m_disknum); 
    530     errno=ENOSYS; 
    531     return -1; 
     533    return set_err(ENOSYS, 
     534      "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" 
     535      "Please contact " PACKAGE_BUGREPORT "\n", (int)m_escalade_type, m_disknum); 
    532536  } 
    533537 
     
    537541  ata->request_id    = 0xFF; 
    538542  ata->unit          = m_disknum; 
    539   ata->status        = 0;            
     543  ata->status        = 0; 
    540544  ata->flags         = 0x1; 
    541   ata->drive_head    = 0x0; 
    542   ata->sector_num    = 0; 
    543  
    544   // All SMART commands use this CL/CH signature.  These are magic 
    545   // values from the ATA specifications. 
    546   ata->cylinder_lo   = 0x4F; 
    547   ata->cylinder_hi   = 0xC2; 
    548  
    549   // SMART ATA COMMAND REGISTER value 
    550   ata->command       = ATA_SMART_CMD; 
     545  // Set registers 
     546  { 
     547    const ata_in_regs_48bit & r = in.in_regs; 
     548    ata->features     = r.features_16; 
     549    ata->sector_count = r.sector_count_16; 
     550    ata->sector_num   = r.lba_low_16; 
     551    ata->cylinder_lo  = r.lba_mid_16; 
     552    ata->cylinder_hi  = r.lba_high_16; 
     553    ata->drive_head   = r.device; 
     554    ata->command      = r.command; 
     555  } 
    551556 
    552557  // Is this a command that reads or returns 512 bytes? 
     
    557562  // 0xF - data command that writes data from host to device 
    558563  // passthru->size values are 0x5 for non-data and 0x07 for data 
    559   if (command == READ_VALUES     || 
    560       command == READ_THRESHOLDS || 
    561       command == READ_LOG        || 
    562       command == IDENTIFY        || 
    563       command == WRITE_LOG )  
    564   { 
    565     readdata=1; 
    566     if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 
    567       cmd_twe->tu_data = data; 
    568       cmd_twe->tu_size = 512; 
    569     } 
    570     ata->sgl_offset = 0x5; 
    571     ata->size         = 0x5; 
     564  bool readdata = false; 
     565  if (in.direction == ata_cmd_in::data_in) { 
     566    readdata=true; 
     567    ata->sgl_offset   = 0x5; 
     568    ata->size         = 0x5; // TODO: other values for multisector? 
    572569    ata->param        = 0xD; 
    573     ata->sector_count = 0x1; 
    574570    // For 64-bit to work correctly, up the size of the command packet 
    575571    // in dwords by 1 to account for the 64-bit single sgl 'address' 
    576572    // field. Note that this doesn't agree with the typedefs but it's 
    577573    // right (agree with kernel driver behavior/typedefs). 
    578     //if (sizeof(long)==8) 
     574    // if (sizeof(long)==8) 
    579575    //  ata->size++; 
    580576  } 
    581   else { 
     577  else if (in.direction == ata_cmd_in::no_data) { 
    582578    // Non data command -- but doesn't use large sector  
    583579    // count register values.   
    584     ata->sgl_offset = 0x0; 
     580    ata->sgl_offset   = 0x0; 
    585581    ata->size         = 0x5; 
    586582    ata->param        = 0x8; 
     
    588584  } 
    589585 
    590   // Now set ATA registers depending upon command 
    591   switch (command){ 
    592   case CHECK_POWER_MODE: 
    593     ata->command     = ATA_CHECK_POWER_MODE; 
    594     ata->features    = 0; 
    595     ata->cylinder_lo = 0; 
    596     ata->cylinder_hi = 0; 
    597     break; 
    598   case READ_VALUES: 
    599     ata->features = ATA_SMART_READ_VALUES; 
    600     break; 
    601   case READ_THRESHOLDS: 
    602     ata->features = ATA_SMART_READ_THRESHOLDS; 
    603     break; 
    604   case READ_LOG: 
    605     ata->features = ATA_SMART_READ_LOG_SECTOR; 
    606     // log number to return 
    607     ata->sector_num  = select; 
    608     break; 
    609   case WRITE_LOG: 
    610     readdata=0; 
    611     ata->features     = ATA_SMART_WRITE_LOG_SECTOR; 
    612     ata->sector_count = 1; 
    613     ata->sector_num   = select; 
    614     ata->param        = 0xF;  // PIO data write 
    615     break; 
    616   case IDENTIFY: 
    617     // ATA IDENTIFY DEVICE 
    618     ata->command     = ATA_IDENTIFY_DEVICE; 
    619     ata->features    = 0; 
    620     ata->cylinder_lo = 0; 
    621     ata->cylinder_hi = 0; 
    622     break; 
    623   case PIDENTIFY: 
    624     // 3WARE controller can NOT have packet device internally 
    625     pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum); 
    626     errno=ENODEV; 
    627     return -1; 
    628   case ENABLE: 
    629     ata->features = ATA_SMART_ENABLE; 
    630     break; 
    631   case DISABLE: 
    632     ata->features = ATA_SMART_DISABLE; 
    633     break; 
    634   case AUTO_OFFLINE: 
    635     ata->features     = ATA_SMART_AUTO_OFFLINE; 
    636     // Enable or disable? 
    637     ata->sector_count = select; 
    638     break; 
    639   case AUTOSAVE: 
    640     ata->features     = ATA_SMART_AUTOSAVE; 
    641     // Enable or disable? 
    642     ata->sector_count = select; 
    643     break; 
    644   case IMMEDIATE_OFFLINE: 
    645     ata->features    = ATA_SMART_IMMEDIATE_OFFLINE; 
    646     // What test type to run? 
    647     ata->sector_num  = select; 
    648     break; 
    649   case STATUS_CHECK: 
    650     ata->features = ATA_SMART_STATUS; 
    651     break; 
    652   case STATUS: 
    653     // This is JUST to see if SMART is enabled, by giving SMART status 
    654     // command. But it doesn't say if status was good, or failing. 
    655     // See below for the difference. 
    656     ata->features = ATA_SMART_STATUS; 
    657     break; 
    658   default: 
    659     pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n" 
    660          "Please contact " PACKAGE_BUGREPORT "\n", command, m_disknum); 
    661     errno=ENOSYS; 
    662     return -1; 
     586  else if (in.direction == ata_cmd_in::data_out) { 
     587    // Non data command -- but doesn't use large sector  
     588    // count register values. 
     589    ata->sgl_offset   = 0x5; 
     590    ata->size         = 0x5; // TODO: not valid for multisector 
     591    ata->param        = 0xF; // PIO data write 
     592    if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 
     593      cmd_twe->tu_data = in.buffer; 
     594      cmd_twe->tu_size = in.size; 
     595    } 
     596    else if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { 
     597       cmd_twa->pdata = in.buffer; 
     598       cmd_twa->driver_pkt.buffer_length = in.size; 
     599    } 
    663600  } 
    664601 
    665602  // Now send the command down through an ioctl() 
     603  int ioctlreturn; 
    666604  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { 
    667605    ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa); 
     
    672610  // Deal with the different error cases 
    673611  if (ioctlreturn) { 
    674     if (!errno) 
    675       errno=EIO; 
    676     return -1; 
     612    return set_err(EIO); 
    677613  } 
    678614 
     
    691627  if (ata->status || (ata->command & 0x21)) { 
    692628    pout("Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",ata->status,ata->command,ata->flags); 
    693     errno=EIO; 
    694     return -1; 
     629    return set_err(EIO); 
    695630  } 
    696631 
     
    698633  if (readdata) { 
    699634    if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) 
    700       memcpy(data, cmd_twa->pdata, 512); 
    701   } 
    702  
    703   // For STATUS_CHECK, we need to check register values 
    704   if (command==STATUS_CHECK) { 
    705  
    706     // To find out if the SMART RETURN STATUS is good or failing, we 
    707     // need to examine the values of the Cylinder Low and Cylinder 
    708     // High Registers. 
    709  
    710     unsigned short cyl_lo=ata->cylinder_lo; 
    711     unsigned short cyl_hi=ata->cylinder_hi; 
    712  
    713     // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good. 
    714     if (cyl_lo==0x4F && cyl_hi==0xC2) 
    715       return 0; 
    716  
    717     // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL 
    718     if (cyl_lo==0xF4 && cyl_hi==0x2C) 
    719       return 1; 
    720  
    721       errno=EIO; 
    722       return -1; 
    723   } 
    724  
    725   // copy sector count register (one byte!) to return data 
    726   if (command==CHECK_POWER_MODE) 
    727     *data=*(char *)&(ata->sector_count); 
    728  
     635      memcpy(in.buffer, cmd_twa->pdata, in.size); 
     636    else if(m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 
     637      memcpy(in.buffer, cmd_twe->tu_data, in.size); // untested 
     638    } 
     639  } 
     640  // Return register values 
     641  if (ata) { 
     642    ata_out_regs_48bit & r = out.out_regs; 
     643    r.error           = ata->features; 
     644    r.sector_count_16 = ata->sector_count; 
     645    r.lba_low_16      = ata->sector_num; 
     646    r.lba_mid_16      = ata->cylinder_lo; 
     647    r.lba_high_16     = ata->cylinder_hi; 
     648    r.device          = ata->drive_head; 
     649    r.status          = ata->command; 
     650  } 
    729651  // look for nonexistent devices/ports 
    730   if (command==IDENTIFY && !nonempty(data, 512)) { 
    731     errno=ENODEV; 
    732     return -1; 
    733   } 
    734  
    735   return 0; 
     652  if (in.in_regs.command == ATA_IDENTIFY_DEVICE 
     653  && !nonempty((unsigned char *)in.buffer, in.size)) { 
     654    return set_err(ENODEV, "No drive on port %d", m_disknum); 
     655  } 
     656  return true; 
    736657} 
    737658