smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
os_freebsd.cpp
Go to the documentation of this file.
00001 /*
00002  * os_freebsd.c
00003  *
00004  * Home page of code is: http://smartmontools.sourceforge.net
00005  *
00006  * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  */
00017 
00018 #include <stdio.h>
00019 #include <sys/types.h>
00020 #include <dirent.h>
00021 #include <fcntl.h>
00022 #include <err.h>
00023 #include <errno.h>
00024 #include <camlib.h>
00025 #include <cam/scsi/scsi_message.h>
00026 #include <cam/scsi/scsi_pass.h>
00027 #if defined(__DragonFly__)
00028 #include <sys/nata.h>
00029 #else
00030 #include <sys/ata.h>
00031 #endif
00032 #include <sys/stat.h>
00033 #include <unistd.h>
00034 #include <glob.h>
00035 #include <stddef.h>
00036 #include <paths.h>
00037 #include <sys/utsname.h>
00038 
00039 #include "config.h"
00040 #include "int64.h"
00041 #include "atacmds.h"
00042 #include "scsicmds.h"
00043 #include "cciss.h"
00044 #include "utility.h"
00045 #include "os_freebsd.h"
00046 
00047 #include "dev_interface.h"
00048 #include "dev_ata_cmd_set.h"
00049 #include "dev_areca.h"
00050 
00051 #define USBDEV "/dev/usb"
00052 #if defined(__FreeBSD_version)
00053 
00054 // This way we define one variable for the GNU/kFreeBSD and FreeBSD 
00055 #define FREEBSDVER __FreeBSD_version
00056 #else
00057 #define FREEBSDVER __FreeBSD_kernel_version
00058 #endif
00059 
00060 #if (FREEBSDVER >= 800000)
00061 #include <libusb20_desc.h>
00062 #include <libusb20.h>
00063 #elif defined(__DragonFly__)
00064 #include <bus/usb/usb.h>
00065 #include <bus/usb/usbhid.h>
00066 #else
00067 #include <dev/usb/usb.h>
00068 #include <dev/usb/usbhid.h>
00069 #endif
00070 
00071 #define CONTROLLER_3WARE_9000_CHAR      0x01
00072 #define CONTROLLER_3WARE_678K_CHAR      0x02
00073 
00074 #ifndef PATHINQ_SETTINGS_SIZE
00075 #define PATHINQ_SETTINGS_SIZE   128
00076 #endif
00077 
00078 const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3874 2014-02-18 00:47:23Z samm2 $" \
00079 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
00080 
00081 #define NO_RETURN 0
00082 #define BAD_SMART 1
00083 #define NO_DISK_3WARE 2
00084 #define BAD_KERNEL 3
00085 #define MAX_MSG 3
00086 
00087 // Utility function for printing warnings
00088 void printwarning(int msgNo, const char* extra) {
00089   static int printed[] = {0,0,0,0};
00090   static const char* message[]={
00091     "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n",
00092 
00093     "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
00094 
00095     "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
00096 
00097     "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
00098   };
00099 
00100   if (msgNo >= 0 && msgNo <= MAX_MSG) {
00101     if (!printed[msgNo]) {
00102       printed[msgNo] = 1;
00103       pout("%s", message[msgNo]);
00104       if (extra)
00105         pout("%s",extra);
00106     }
00107   }
00108   return;
00109 }
00110 
00111 // Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
00112 
00113 #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
00114 #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
00115 #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
00116 
00117 #ifndef ATA_DEVICE
00118 #define ATA_DEVICE "/dev/ata"
00119 #endif
00120 
00121 #define ARGUSED(x) ((void)(x))
00122 
00123 // global variable holding byte count of allocated memory
00124 long long bytes;
00125 extern unsigned char failuretest_permissive;
00126 
00127 /////////////////////////////////////////////////////////////////////////////
00128 
00129 namespace os_freebsd { // No need to publish anything, name provided for Doxygen
00130 
00131 /////////////////////////////////////////////////////////////////////////////
00132 /// Implement shared open/close routines with old functions.
00133 
00134 class freebsd_smart_device
00135 : virtual public /*implements*/ smart_device
00136 {
00137 public:
00138   explicit freebsd_smart_device()
00139     : smart_device(never_called),
00140       m_fd(-1) { }
00141 
00142   virtual ~freebsd_smart_device() throw();
00143 
00144   virtual bool is_open() const;
00145 
00146   virtual bool open();
00147 
00148   virtual bool close();
00149 
00150 protected:
00151   /// Return filedesc for derived classes.
00152   int get_fd() const
00153     { return m_fd; }
00154 
00155   void set_fd(int fd)
00156     { m_fd = fd; }
00157 
00158 private:
00159   int m_fd; ///< filedesc, -1 if not open.
00160 };
00161 
00162 #ifdef __GLIBC__
00163 static inline void * reallocf(void *ptr, size_t size) {
00164    void *rv = realloc(ptr, size);
00165    if((rv == NULL) && (size != 0))
00166      free(ptr);
00167    return rv;
00168    }
00169 #endif
00170 
00171 freebsd_smart_device::~freebsd_smart_device() throw()
00172 {
00173   if (m_fd >= 0)
00174     os_freebsd::freebsd_smart_device::close();
00175 }
00176 
00177 // migration from the old_style 
00178 unsigned char m_controller_type;
00179 unsigned char m_controller_port; 
00180 
00181 // examples for smartctl
00182 static const char  smartctl_examples[] =
00183    "=================================================== SMARTCTL EXAMPLES =====\n\n"
00184          "  smartctl -a /dev/ad0                       (Prints all SMART information)\n\n"
00185          "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
00186          "                                              (Enables SMART on first disk)\n\n"
00187          "  smartctl -t long /dev/ad0              (Executes extended disk self-test)\n\n"
00188          "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
00189          "                                      (Prints Self-Test & Attribute errors)\n"
00190          "                                      (Prints Self-Test & Attribute errors)\n\n"
00191          "  smartctl -a --device=3ware,2 /dev/twa0\n"
00192          "  smartctl -a --device=3ware,2 /dev/twe0\n"
00193          "  smartctl -a --device=3ware,2 /dev/tws0\n"
00194          "                              (Prints all SMART information for ATA disk on\n"
00195          "                                 third port of first 3ware RAID controller)\n"
00196   "  smartctl -a --device=cciss,0 /dev/ciss0\n"
00197          "                              (Prints all SMART information for first disk \n"
00198          "                               on Common Interface for SCSI-3 Support driver)\n"
00199   "  smartctl -a --device=areca,3/1 /dev/arcmsr0\n"
00200          "                              (Prints all SMART information for 3rd disk in the 1st enclosure \n"
00201          "                               on first ARECA RAID controller)\n"
00202 
00203          ;
00204 
00205 bool freebsd_smart_device::is_open() const
00206 {
00207   return (m_fd >= 0);
00208 }
00209 
00210 
00211 bool freebsd_smart_device::open()
00212 {
00213   const char *dev = get_dev_name();
00214   if ((m_fd = ::open(dev,O_RDONLY))<0) {
00215     set_err(errno);
00216     return false;
00217   }
00218   return true;
00219 }
00220 
00221 bool freebsd_smart_device::close()
00222 {
00223   int failed = 0;
00224   // close device, if open
00225   if (is_open())
00226     failed=::close(get_fd());
00227 
00228   set_fd(-1);
00229 
00230   if(failed) return false;
00231     else return true;
00232 }
00233 
00234 /////////////////////////////////////////////////////////////////////////////
00235 /// Implement standard ATA support
00236 
00237 class freebsd_ata_device
00238 : public /*implements*/ ata_device,
00239   public /*extends*/ freebsd_smart_device
00240 {
00241 public:
00242   freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
00243   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
00244 
00245 protected:
00246   virtual int do_cmd(struct ata_ioc_request* request, bool is_48bit_cmd);
00247 };
00248 
00249 freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
00250 : smart_device(intf, dev_name, "ata", req_type),
00251   freebsd_smart_device()
00252 {
00253 }
00254 
00255 int freebsd_ata_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd)
00256 {
00257   int fd = get_fd(), ret;
00258   ARGUSED(is_48bit_cmd); // no support for 48 bit commands in the IOCATAREQUEST
00259   ret = ioctl(fd, IOCATAREQUEST, request);
00260   if (ret) set_err(errno);
00261   return ret;
00262 }
00263 
00264 
00265 
00266 bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
00267 {
00268   bool ata_48bit = false; // no ata_48bit_support via IOCATAREQUEST
00269   if(!strcmp("atacam",get_dev_type())) // enable for atacam interface
00270     ata_48bit = true;
00271 
00272   if (!ata_cmd_is_ok(in,
00273     true,  // data_out_support
00274     true,  // multi_sector_support
00275     ata_48bit) 
00276     ) {
00277       set_err(ENOSYS, "48-bit ATA commands not implemented for legacy controllers");
00278       return false;
00279     }
00280 
00281   struct ata_ioc_request request;
00282   bzero(&request,sizeof(struct ata_ioc_request));
00283 
00284   request.timeout=SCSI_TIMEOUT_DEFAULT;
00285   request.u.ata.command=in.in_regs.command;
00286   request.u.ata.feature=in.in_regs.features;
00287 
00288   request.u.ata.count = in.in_regs.sector_count_16;
00289   request.u.ata.lba = in.in_regs.lba_48;
00290 
00291   switch (in.direction) {
00292     case ata_cmd_in::no_data:  
00293       request.flags=ATA_CMD_CONTROL;
00294       break;
00295     case ata_cmd_in::data_in:  
00296       request.flags=ATA_CMD_READ | ATA_CMD_CONTROL;
00297       request.data=(char *)in.buffer;
00298       request.count=in.size;
00299       break;
00300     case ata_cmd_in::data_out: 
00301       request.flags=ATA_CMD_WRITE | ATA_CMD_CONTROL;
00302       request.data=(char *)in.buffer;
00303       request.count=in.size;
00304       break;
00305     default:
00306       return set_err(ENOSYS);
00307   }
00308 
00309   clear_err();
00310   errno = 0;
00311   if (do_cmd(&request, in.in_regs.is_48bit_cmd()))
00312       return false;
00313   if (request.error)
00314       return set_err(EIO, "request failed, error code 0x%02x", request.error);
00315 
00316   out.out_regs.error = request.error;
00317   out.out_regs.sector_count_16 = request.u.ata.count;
00318   out.out_regs.lba_48 = request.u.ata.lba;
00319 
00320 
00321   // Command specific processing
00322   if (in.in_regs.command == ATA_SMART_CMD
00323        && in.in_regs.features == ATA_SMART_STATUS
00324        && in.out_needed.lba_high)
00325   {
00326     unsigned const char normal_lo=0x4f, normal_hi=0xc2;
00327     unsigned const char failed_lo=0xf4, failed_hi=0x2c;
00328 
00329     // Cyl low and Cyl high unchanged means "Good SMART status"
00330     if (!(out.out_regs.lba_mid==normal_lo && out.out_regs.lba_high==normal_hi)
00331     // These values mean "Bad SMART status"
00332         && !(out.out_regs.lba_mid==failed_lo && out.out_regs.lba_high==failed_hi))
00333 
00334     {
00335       // We haven't gotten output that makes sense; print out some debugging info
00336       char buf[512];
00337       snprintf(buf, sizeof(buf),
00338         "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
00339         (int)request.u.ata.command,
00340         (int)request.u.ata.feature,
00341         (int)request.u.ata.count,
00342         (int)((request.u.ata.lba) & 0xff),
00343         (int)((request.u.ata.lba>>8) & 0xff),
00344         (int)((request.u.ata.lba>>16) & 0xff),
00345         (int)request.error);
00346       printwarning(BAD_SMART,buf);
00347       out.out_regs.lba_high = failed_hi; 
00348       out.out_regs.lba_mid = failed_lo;
00349     }
00350   }
00351 
00352   return true;
00353 }
00354 
00355 #if FREEBSDVER > 800100
00356 class freebsd_atacam_device : public freebsd_ata_device
00357 {
00358 public:
00359   freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type)
00360   : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type)
00361   {}
00362   
00363   virtual bool open();
00364   virtual bool close();
00365   
00366 protected:
00367   int m_fd;
00368   struct cam_device *m_camdev;
00369 
00370   virtual int do_cmd( struct ata_ioc_request* request , bool is_48bit_cmd);
00371 };
00372 
00373 bool freebsd_atacam_device::open(){
00374   const char *dev = get_dev_name();
00375   
00376   if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
00377     set_err(errno);
00378     return false;
00379   }
00380   set_fd(m_camdev->fd);
00381   return true;
00382 }
00383 
00384 bool freebsd_atacam_device::close(){
00385   cam_close_device(m_camdev);
00386   set_fd(-1);
00387   return true;
00388 }
00389 
00390 int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd)
00391 {
00392   union ccb ccb;
00393   int camflags;
00394 
00395   // FIXME:
00396   // 48bit commands are broken in ATACAM before r242422/HEAD
00397   // and may cause system hang
00398   // Waiting for MFC to make sure that bug is fixed,
00399   // later version check needs to be added
00400   if(!strcmp("ata",m_camdev->sim_name) && is_48bit_cmd) {
00401     set_err(ENOSYS, "48-bit ATA commands not implemented for legacy controllers");
00402     return -1;
00403   }
00404 
00405   memset(&ccb, 0, sizeof(ccb));
00406 
00407   if (request->count == 0)
00408     camflags = CAM_DIR_NONE;
00409   else if (request->flags & ATA_CMD_READ)
00410     camflags = CAM_DIR_IN;
00411   else
00412     camflags = CAM_DIR_OUT;
00413 
00414   cam_fill_ataio(&ccb.ataio,
00415                  0,
00416                  NULL,
00417                  camflags,
00418                  MSG_SIMPLE_Q_TAG,
00419                  (u_int8_t*)request->data,
00420                  request->count,
00421                  request->timeout * 1000); // timeout in seconds
00422 
00423   ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT |
00424     (is_48bit_cmd ? CAM_ATAIO_48BIT : 0);
00425   // ata_28bit_cmd
00426   ccb.ataio.cmd.command = request->u.ata.command;
00427   ccb.ataio.cmd.features = request->u.ata.feature;
00428   ccb.ataio.cmd.lba_low = request->u.ata.lba;
00429   ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8;
00430   ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16;
00431   // ata_48bit cmd
00432   ccb.ataio.cmd.lba_low_exp = request->u.ata.lba >> 24;
00433   ccb.ataio.cmd.lba_mid_exp = request->u.ata.lba >> 32;
00434   ccb.ataio.cmd.lba_high_exp = request->u.ata.lba >> 40;
00435   ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f);
00436   ccb.ataio.cmd.sector_count = request->u.ata.count;
00437   ccb.ataio.cmd.sector_count_exp = request->u.ata.count  >> 8;;
00438 
00439   ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
00440 
00441   if (cam_send_ccb(m_camdev, &ccb) < 0) {
00442     set_err(EIO, "cam_send_ccb failed");
00443     return -1;
00444   }
00445 
00446   if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
00447     if(scsi_debugmode > 0)
00448       cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
00449     set_err(EIO);
00450     return -1;
00451   }
00452 
00453   request->u.ata.lba =
00454     ((u_int64_t)(ccb.ataio.res.lba_low)) |
00455     ((u_int64_t)(ccb.ataio.res.lba_mid) << 8) |
00456     ((u_int64_t)(ccb.ataio.res.lba_high) << 16) |
00457     ((u_int64_t)(ccb.ataio.res.lba_low_exp) << 24) |
00458     ((u_int64_t)(ccb.ataio.res.lba_mid_exp) << 32) |
00459     ((u_int64_t)(ccb.ataio.res.lba_high_exp) << 40);
00460 
00461   request->u.ata.count = ccb.ataio.res.sector_count | (ccb.ataio.res.sector_count_exp << 8);
00462   request->error = ccb.ataio.res.error;
00463 
00464   return 0;
00465 }
00466 
00467 #endif
00468 
00469 /////////////////////////////////////////////////////////////////////////////
00470 /// Implement AMCC/3ware RAID support
00471 
00472 class freebsd_escalade_device
00473 : public /*implements*/ ata_device,
00474   public /*extends*/ freebsd_smart_device
00475 {
00476 public:
00477   freebsd_escalade_device(smart_interface * intf, const char * dev_name,
00478     int escalade_type, int disknum);
00479 
00480 protected:
00481   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
00482   virtual bool open();
00483 
00484 private:
00485   int m_escalade_type; ///< Type string for escalade_command_interface().
00486   int m_disknum; ///< Disk number.
00487 };
00488 
00489 freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name,
00490     int escalade_type, int disknum)
00491 : smart_device(intf, dev_name, "3ware", "3ware"),
00492   freebsd_smart_device(),
00493   m_escalade_type(escalade_type), m_disknum(disknum)
00494 {
00495   set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
00496 }
00497 
00498 bool freebsd_escalade_device::open()
00499 {
00500   const char *dev = get_dev_name();
00501   int fd;
00502   
00503   if ((fd = ::open(dev,O_RDWR))<0) {
00504     set_err(errno);
00505     return false;
00506   }
00507   set_fd(fd);
00508   return true;
00509 }
00510 
00511 bool freebsd_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
00512 {
00513   // to hold true file descriptor
00514   int fd = get_fd();
00515 
00516   if (!ata_cmd_is_ok(in,
00517     true, // data_out_support
00518     false, // TODO: multi_sector_support
00519     true) // ata_48bit_support
00520   )
00521   return false;
00522 
00523   struct twe_usercommand* cmd_twe = NULL;
00524   TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
00525   TWE_Command_ATA* ata = NULL;
00526 
00527   // Used by both the SCSI and char interfaces
00528   char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
00529 
00530   if (m_disknum < 0) {
00531     printwarning(NO_DISK_3WARE,NULL);
00532     return -1;
00533   }
00534 
00535   memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
00536 
00537   if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
00538     cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
00539     cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
00540     cmd_twa->driver_pkt.buffer_length = in.size;
00541     // using "old" packet format to speak with SATA devices
00542     ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
00543   } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
00544     cmd_twe = (struct twe_usercommand*)ioctl_buffer;
00545     ata = &cmd_twe->tu_command.ata;
00546   } else {
00547     return set_err(ENOSYS,
00548       "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n"
00549       "Please contact " PACKAGE_BUGREPORT "\n", (int)m_escalade_type, m_disknum);
00550   }
00551 
00552   ata->opcode = TWE_OP_ATA_PASSTHROUGH;
00553 
00554   // Same for (almost) all commands - but some reset below
00555   ata->request_id    = 0xFF;
00556   ata->unit          = m_disknum;
00557   ata->status        = 0;
00558   ata->flags         = 0x1;
00559   ata->size         = 0x5; // TODO: multisector support
00560   // Set registers
00561   {
00562     const ata_in_regs_48bit & r = in.in_regs;
00563     ata->features     = r.features_16;
00564     ata->sector_count = r.sector_count_16;
00565     ata->sector_num   = r.lba_low_16;
00566     ata->cylinder_lo  = r.lba_mid_16;
00567     ata->cylinder_hi  = r.lba_high_16;
00568     ata->drive_head   = r.device;
00569     ata->command      = r.command;
00570   }
00571 
00572   // Is this a command that reads or returns 512 bytes?
00573   // passthru->param values are:
00574   // 0x0 - non data command without TFR write check,
00575   // 0x8 - non data command with TFR write check,
00576   // 0xD - data command that returns data to host from device
00577   // 0xF - data command that writes data from host to device
00578   // passthru->size values are 0x5 for non-data and 0x07 for data
00579   bool readdata = false;
00580   if (in.direction == ata_cmd_in::data_in) {
00581     if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
00582       cmd_twe->tu_data = in.buffer;
00583       cmd_twe->tu_size = 512;
00584     }
00585 
00586     readdata=true;
00587     ata->sgl_offset   = 0x5;
00588     ata->param        = 0xD;
00589     // For 64-bit to work correctly, up the size of the command packet
00590     // in dwords by 1 to account for the 64-bit single sgl 'address'
00591     // field. Note that this doesn't agree with the typedefs but it's
00592     // right (agree with kernel driver behavior/typedefs).
00593     // if (sizeof(long)==8)
00594     //  ata->size++;
00595   }
00596   else if (in.direction == ata_cmd_in::no_data) {
00597     // Non data command -- but doesn't use large sector 
00598     // count register values.
00599     ata->sgl_offset   = 0x0;
00600     ata->param        = 0x8;
00601     ata->sector_count = 0x0;
00602   }
00603   else if (in.direction == ata_cmd_in::data_out) {
00604     ata->sgl_offset   = 0x5;
00605     ata->param        = 0xF; // PIO data write
00606     if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
00607       cmd_twe->tu_data = in.buffer;
00608       cmd_twe->tu_size = 512;
00609     }
00610     else if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
00611        memcpy(cmd_twa->pdata, in.buffer, in.size);
00612     }
00613   }
00614   else
00615     return set_err(EINVAL);
00616 
00617   // 3WARE controller can NOT have packet device internally
00618   if (in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE) {
00619     return set_err(ENODEV, "No drive on port %d", m_disknum);
00620   }
00621 
00622   // Now send the command down through an ioctl()
00623   int ioctlreturn;
00624   if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
00625     ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
00626   } else {
00627     ioctlreturn=ioctl(fd,TWEIO_COMMAND,cmd_twe);
00628   }
00629 
00630   // Deal with the different error cases
00631   if (ioctlreturn) {
00632     return set_err(EIO);
00633   }
00634 
00635   // See if the ATA command failed.  Now that we have returned from
00636   // the ioctl() call, if passthru is valid, then:
00637   // - ata->status contains the 3ware controller STATUS
00638   // - ata->command contains the ATA STATUS register
00639   // - ata->features contains the ATA ERROR register
00640   //
00641   // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
00642   // If bit 0 (error bit) is set, then ATA ERROR register is valid.
00643   // While we *might* decode the ATA ERROR register, at the moment it
00644   // doesn't make much sense: we don't care in detail why the error
00645   // happened.
00646 
00647   if (ata->status || (ata->command & 0x21)) {
00648     if (scsi_debugmode)
00649       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);
00650     return set_err(EIO);
00651   }
00652 
00653   // If this is a read data command, copy data to output buffer
00654   if (readdata) {
00655     if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR)
00656       memcpy(in.buffer, cmd_twa->pdata, in.size);
00657     else if(m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
00658       memcpy(in.buffer, cmd_twe->tu_data, in.size); // untested
00659     }
00660   }
00661   // Return register values
00662   if (ata) {
00663     ata_out_regs_48bit & r = out.out_regs;
00664     r.error           = ata->features;
00665     r.sector_count_16 = ata->sector_count;
00666     r.lba_low_16      = ata->sector_num;
00667     r.lba_mid_16      = ata->cylinder_lo;
00668     r.lba_high_16     = ata->cylinder_hi;
00669     r.device          = ata->drive_head;
00670     r.status          = ata->command;
00671   }
00672   // look for nonexistent devices/ports
00673   if (in.in_regs.command == ATA_IDENTIFY_DEVICE
00674   && !nonempty((unsigned char *)in.buffer, in.size)) {
00675     return set_err(ENODEV, "No drive on port %d", m_disknum);
00676   }
00677   return true;
00678 }
00679 
00680 
00681 /////////////////////////////////////////////////////////////////////////////
00682 /// Implement Highpoint RAID support with old functions
00683 
00684 class freebsd_highpoint_device
00685 : public /*implements*/ ata_device_with_command_set,
00686   public /*extends*/ freebsd_smart_device
00687 {
00688 public:
00689   freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
00690     unsigned char controller, unsigned char channel, unsigned char port);
00691 
00692 protected:
00693   virtual int ata_command_interface(smart_command_set command, int select, char * data);
00694   virtual bool open();
00695 
00696 private:
00697   unsigned char m_hpt_data[3]; ///< controller/channel/port
00698 };
00699 
00700 
00701 freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
00702   unsigned char controller, unsigned char channel, unsigned char port)
00703 : smart_device(intf, dev_name, "hpt", "hpt"),
00704   freebsd_smart_device()
00705 {
00706   m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port;
00707   set_info().info_name = strprintf("%s [hpt_disk_%u/%u/%u]", dev_name, m_hpt_data[0], m_hpt_data[1], m_hpt_data[2]);
00708 }
00709 
00710 bool freebsd_highpoint_device::open()
00711 {
00712   const char *dev = get_dev_name();
00713   int fd;
00714   
00715   if ((fd = ::open(dev,O_RDWR))<0) {
00716     set_err(errno);
00717     return false;
00718   }
00719   set_fd(fd);
00720   return true;
00721 }
00722 
00723 int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
00724 {
00725   int fd=get_fd(); 
00726   int ids[2];
00727   HPT_IOCTL_PARAM param;
00728   HPT_CHANNEL_INFO_V2 info;
00729   unsigned char* buff[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)];
00730   PHPT_PASS_THROUGH_HEADER pide_pt_hdr, pide_pt_hdr_out;
00731 
00732   // get internal deviceid
00733   ids[0] = m_hpt_data[0] - 1;
00734   ids[1] = m_hpt_data[1] - 1;
00735 
00736   memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
00737 
00738   param.magic = HPT_IOCTL_MAGIC;
00739   param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO_V2;
00740   param.in = (unsigned char *)ids;
00741   param.in_size = sizeof(unsigned int) * 2;
00742   param.out = (unsigned char *)&info;
00743   param.out_size = sizeof(HPT_CHANNEL_INFO_V2);
00744 
00745   if (m_hpt_data[2]==1) {
00746     param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO;
00747     param.out_size = sizeof(HPT_CHANNEL_INFO);
00748   }
00749   if (ioctl(fd, HPT_DO_IOCONTROL, &param)!=0 ||
00750       info.devices[m_hpt_data[2]-1]==0) {
00751     return -1;
00752   }
00753 
00754   // perform smart action
00755   memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER));
00756   pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff;
00757 
00758   pide_pt_hdr->lbamid = 0x4f;
00759   pide_pt_hdr->lbahigh = 0xc2;
00760   pide_pt_hdr->command = ATA_SMART_CMD;
00761   pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1];
00762 
00763   switch (command){
00764   case READ_VALUES:
00765     pide_pt_hdr->feature=ATA_SMART_READ_VALUES;
00766     pide_pt_hdr->protocol=HPT_READ;
00767     break;
00768   case READ_THRESHOLDS:
00769     pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS;
00770     pide_pt_hdr->protocol=HPT_READ;
00771     break;
00772   case READ_LOG:
00773     pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR;
00774     pide_pt_hdr->lbalow=select;
00775     pide_pt_hdr->protocol=HPT_READ;
00776     break;
00777   case IDENTIFY:
00778     pide_pt_hdr->command=ATA_IDENTIFY_DEVICE;
00779     pide_pt_hdr->protocol=HPT_READ;
00780     break;
00781   case ENABLE:
00782     pide_pt_hdr->feature=ATA_SMART_ENABLE;
00783     break;
00784   case DISABLE:
00785     pide_pt_hdr->feature=ATA_SMART_DISABLE;
00786     break;
00787   case AUTO_OFFLINE:
00788     pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE;
00789     pide_pt_hdr->sectorcount=select;
00790     break;
00791   case AUTOSAVE:
00792     pide_pt_hdr->feature=ATA_SMART_AUTOSAVE;
00793     pide_pt_hdr->sectorcount=select;
00794     break;
00795   case IMMEDIATE_OFFLINE:
00796     pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE;
00797     pide_pt_hdr->lbalow=select;
00798     break;
00799   case STATUS_CHECK:
00800   case STATUS:
00801     pide_pt_hdr->feature=ATA_SMART_STATUS;
00802     break;
00803   case CHECK_POWER_MODE:
00804     pide_pt_hdr->command=ATA_CHECK_POWER_MODE;
00805     break;
00806   case WRITE_LOG:
00807     memcpy(buff+sizeof(HPT_PASS_THROUGH_HEADER), data, 512);
00808     pide_pt_hdr->feature=ATA_SMART_WRITE_LOG_SECTOR;
00809     pide_pt_hdr->lbalow=select;
00810     pide_pt_hdr->protocol=HPT_WRITE;
00811     break;
00812   default:
00813     pout("Unrecognized command %d in highpoint_command_interface()\n"
00814          "Please contact " PACKAGE_BUGREPORT "\n", command);
00815     errno=ENOSYS;
00816     return -1;
00817   }
00818   if (pide_pt_hdr->protocol!=0) {
00819     pide_pt_hdr->sectors = 1;
00820     pide_pt_hdr->sectorcount = 1;
00821   }
00822 
00823   memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
00824 
00825   param.magic = HPT_IOCTL_MAGIC;
00826   param.ctrl_code = HPT_IOCTL_IDE_PASS_THROUGH;
00827   param.in = (unsigned char *)buff;
00828   param.in_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? 0 : pide_pt_hdr->sectors * 512);
00829   param.out = (unsigned char *)buff+param.in_size;
00830   param.out_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? pide_pt_hdr->sectors * 512 : 0);
00831 
00832   pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out;
00833 
00834   if ((ioctl(fd, HPT_DO_IOCONTROL, &param)!=0) ||
00835       (pide_pt_hdr_out->command & 1)) {
00836     return -1;
00837   }
00838 
00839   if (command==STATUS_CHECK)
00840   {
00841     unsigned const char normal_lo=0x4f, normal_hi=0xc2;
00842     unsigned const char failed_lo=0xf4, failed_hi=0x2c;
00843     unsigned char low,high;
00844 
00845     high = pide_pt_hdr_out->lbahigh;
00846     low = pide_pt_hdr_out->lbamid;
00847 
00848     // Cyl low and Cyl high unchanged means "Good SMART status"
00849     if (low==normal_lo && high==normal_hi)
00850       return 0;
00851 
00852     // These values mean "Bad SMART status"
00853     if (low==failed_lo && high==failed_hi)
00854       return 1;
00855 
00856     // We haven't gotten output that makes sense; print out some debugging info
00857     char buf[512];
00858     snprintf(buf, sizeof(buf),
00859             "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
00860             (int)pide_pt_hdr_out->command,
00861             (int)pide_pt_hdr_out->feature,
00862             (int)pide_pt_hdr_out->sectorcount,
00863             (int)pide_pt_hdr_out->lbalow,
00864             (int)pide_pt_hdr_out->lbamid,
00865             (int)pide_pt_hdr_out->lbahigh,
00866             (int)pide_pt_hdr_out->sectors);
00867     printwarning(BAD_SMART,buf);
00868   }
00869   else if (command==CHECK_POWER_MODE)
00870     data[0] = pide_pt_hdr_out->sectorcount & 0xff;
00871   else if (pide_pt_hdr->protocol==HPT_READ)
00872     memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER), 
00873       pide_pt_hdr->sectors * 512);
00874   return 0;
00875 }
00876 
00877 
00878 /////////////////////////////////////////////////////////////////////////////
00879 /// Standard SCSI support
00880 
00881 class freebsd_scsi_device
00882 : public /*implements*/ scsi_device,
00883   public /*extends*/ freebsd_smart_device
00884 {
00885 public:
00886   freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
00887 
00888   virtual smart_device * autodetect_open();
00889 
00890   virtual bool scsi_pass_through(scsi_cmnd_io * iop);
00891   
00892   virtual bool open();
00893 
00894   virtual bool close();
00895   
00896 private:
00897   struct cam_device *m_camdev;
00898 };
00899 
00900 bool freebsd_scsi_device::open(){
00901   const char *dev = get_dev_name();
00902   
00903   if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
00904     set_err(errno);
00905     return false;
00906   }
00907   set_fd(m_camdev->fd);
00908   return true;
00909 }
00910 
00911 bool freebsd_scsi_device::close(){
00912   cam_close_device(m_camdev);
00913   set_fd(-1);
00914   return true;
00915 }
00916 
00917 freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
00918   const char * dev_name, const char * req_type)
00919 : smart_device(intf, dev_name, "scsi", req_type),
00920   freebsd_smart_device()
00921 {
00922 }
00923 
00924 
00925 bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
00926 {
00927   union ccb *ccb;
00928 
00929   if (scsi_debugmode) {
00930     unsigned int k;
00931     const unsigned char * ucp = iop->cmnd;
00932     const char * np;
00933 
00934     np = scsi_get_opcode_name(ucp[0]);
00935     pout(" [%s: ", np ? np : "<unknown opcode>");
00936     for (k = 0; k < iop->cmnd_len; ++k)
00937       pout("%02x ", ucp[k]);
00938     if ((scsi_debugmode > 1) && 
00939       (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
00940     int trunc = (iop->dxfer_len > 256) ? 1 : 0;
00941 
00942     pout("]\n  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
00943       (trunc ? " [only first 256 bytes shown]" : ""));
00944     dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
00945       }
00946       else
00947         pout("]\n");
00948   }
00949 
00950   if(m_camdev==NULL) {
00951     if (scsi_debugmode)
00952       pout("  error: camdev=0!\n");
00953     return set_err(ENOTTY);
00954   }
00955 
00956   if (!(ccb = cam_getccb(m_camdev))) {
00957     if (scsi_debugmode)
00958       pout("  error allocating ccb\n");
00959     return set_err(ENOMEM);
00960   }
00961 
00962   // mfi SAT layer is known to be buggy
00963   if(!strcmp("mfi",m_camdev->sim_name)) {
00964     if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { 
00965       // Controller does not return ATA output registers in SAT sense data
00966       if (iop->cmnd[2] & (1 << 5)) // chk_cond
00967         return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware");
00968     }
00969     // SMART WRITE LOG SECTOR causing media errors
00970     if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16
00971         && iop->cmnd[14] == ATA_SMART_CMD  && iop->cmnd[3]==0 &&
00972         iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) ||
00973         (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12
00974         && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR))
00975     {
00976       if(!failuretest_permissive)
00977         return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); 
00978     }
00979   }
00980   // clear out structure, except for header that was filled in for us
00981   bzero(&(&ccb->ccb_h)[1],
00982     sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
00983 
00984   cam_fill_csio(&ccb->csio,
00985     /* retries */ 1,
00986     /* cbfcnp */ NULL,
00987     /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)),
00988     /* tagaction */ MSG_SIMPLE_Q_TAG,
00989     /* dataptr */ iop->dxferp,
00990     /* datalen */ iop->dxfer_len,
00991     /* senselen */ iop->max_sense_len,
00992     /* cdblen */ iop->cmnd_len,
00993     /* timout (converted to seconds) */ iop->timeout*1000);
00994   memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len);
00995 
00996   if (cam_send_ccb(m_camdev,ccb) < 0) {
00997     if (scsi_debugmode) {
00998       pout("  error sending SCSI ccb\n");
00999       cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
01000     }
01001     cam_freeccb(ccb);
01002     return set_err(EIO);
01003   }
01004 
01005   if (scsi_debugmode) {
01006     pout("  CAM status=0x%x, SCSI status=0x%x, resid=0x%x\n",
01007          ccb->ccb_h.status, ccb->csio.scsi_status, ccb->csio.resid);
01008     if ((scsi_debugmode > 1) && (DXFER_FROM_DEVICE == iop->dxfer_dir)) {
01009       int trunc, len;
01010 
01011       len = iop->dxfer_len - ccb->csio.resid;
01012       trunc = (len > 256) ? 1 : 0;
01013       if (len > 0) {
01014         pout("  Incoming data, len=%d%s:\n", len,
01015              (trunc ? " [only first 256 bytes shown]" : ""));
01016         dStrHex(iop->dxferp, (trunc ? 256 : len), 1);
01017       }
01018       else
01019         pout("  Incoming data trimmed to nothing by resid\n");
01020     }
01021   }
01022 
01023   if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) {
01024     if (scsi_debugmode)
01025       cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
01026     cam_freeccb(ccb);
01027     return set_err(EIO);
01028   }
01029 
01030   iop->resid = ccb->csio.resid;
01031   iop->scsi_status = ccb->csio.scsi_status;
01032   if (iop->sensep && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) {
01033     if (scsi_debugmode)
01034       pout("  sense_len=0x%x, sense_resid=0x%x\n",
01035            ccb->csio.sense_len, ccb->csio.sense_resid);
01036     iop->resp_sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
01037     /* Some SCSI controller device drivers miscalculate the sense_resid
01038        field so cap resp_sense_len on max_sense_len. */
01039     if (iop->resp_sense_len > iop->max_sense_len)
01040       iop->resp_sense_len = iop->max_sense_len;
01041     if (iop->resp_sense_len > 0) {
01042       memcpy(iop->sensep, &(ccb->csio.sense_data), iop->resp_sense_len);
01043       if (scsi_debugmode) {
01044         if (scsi_debugmode > 1) {
01045           pout("  >>> Sense buffer, len=%lu:\n", iop->resp_sense_len);
01046           dStrHex(iop->sensep, iop->resp_sense_len, 1);
01047         }
01048         if ((iop->sensep[0] & 0x7f) > 0x71)
01049           pout("  status=0x%x: [desc] sense_key=0x%x asc=0x%x ascq=0x%x\n",
01050                iop->scsi_status, iop->sensep[1] & 0xf,
01051                iop->sensep[2], iop->sensep[3]);
01052         else
01053           pout("  status=0x%x: sense_key=0x%x asc=0x%x ascq=0x%x\n",
01054                iop->scsi_status, iop->sensep[2] & 0xf,
01055                iop->sensep[12], iop->sensep[13]);
01056       }
01057     }
01058     else if (scsi_debugmode)
01059       pout("  status=0x%x\n", iop->scsi_status);
01060   }
01061   else if (scsi_debugmode)
01062     pout("  status=0x%x\n", iop->scsi_status);
01063 
01064   cam_freeccb(ccb);
01065 
01066   // mfip replacing PDT of the device so response does not make a sense
01067   // this sets PDT to 00h - direct-access block device
01068   if((!strcmp("mfi", m_camdev->sim_name) || !strcmp("mpt", m_camdev->sim_name))
01069    && iop->cmnd[0] == INQUIRY) {
01070      if (scsi_debugmode) {
01071         pout("  device on %s controller, patching PDT\n", m_camdev->sim_name);
01072      }
01073      iop->dxferp[0] = iop->dxferp[0] & 0xe0;
01074   }
01075 
01076   return true;
01077 }
01078 
01079 
01080 /////////////////////////////////////////////////////////////////////////////
01081 /// Areca RAID support
01082 
01083 ///////////////////////////////////////////////////////////////////
01084 // SATA(ATA) device behind Areca RAID Controller
01085 class freebsd_areca_ata_device
01086 : public /*implements*/ areca_ata_device,
01087   public /*extends*/ freebsd_smart_device
01088 {
01089 public:
01090   freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
01091   virtual smart_device * autodetect_open();
01092   virtual bool arcmsr_lock();
01093   virtual bool arcmsr_unlock();
01094   virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
01095 };
01096 
01097 ///////////////////////////////////////////////////////////////////
01098 // SAS(SCSI) device behind Areca RAID Controller
01099 class freebsd_areca_scsi_device
01100 : public /*implements*/ areca_scsi_device,
01101   public /*extends*/ freebsd_smart_device
01102 {
01103 public:
01104   freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
01105   virtual smart_device * autodetect_open();
01106   virtual bool arcmsr_lock();
01107   virtual bool arcmsr_unlock();
01108   virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
01109 };
01110 
01111 
01112 // Areca RAID Controller(SATA Disk)
01113 freebsd_areca_ata_device::freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
01114 : smart_device(intf, dev_name, "areca", "areca"),
01115   freebsd_smart_device()
01116 {
01117   set_disknum(disknum);
01118   set_encnum(encnum);
01119   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
01120 }
01121 
01122 
01123 smart_device * freebsd_areca_ata_device::autodetect_open()
01124 {
01125   int is_ata = 1;
01126 
01127   // autodetect device type
01128   is_ata = arcmsr_get_dev_type();
01129   if(is_ata < 0)
01130   {
01131     set_err(EIO);
01132     return this;
01133   }
01134 
01135   if(is_ata == 1)
01136   {
01137     // SATA device
01138     return this;
01139   }
01140 
01141   // SAS device
01142   smart_device_auto_ptr newdev(new freebsd_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
01143   close();
01144   delete this;
01145   newdev->open();       // TODO: Can possibly pass open fd
01146 
01147   return newdev.release();
01148 }
01149 
01150 int freebsd_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
01151 {
01152   int ioctlreturn = 0;
01153 
01154   if(!is_open()) {
01155       if(!open()){
01156       }
01157   }
01158 
01159   ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp);
01160   if (ioctlreturn)
01161   {
01162     // errors found
01163     return -1;
01164   }
01165 
01166   return ioctlreturn;
01167 }
01168 
01169 bool freebsd_areca_ata_device::arcmsr_lock()
01170 {
01171   return true;
01172 }
01173 
01174 
01175 bool freebsd_areca_ata_device::arcmsr_unlock()
01176 {
01177   return true;
01178 }
01179 
01180 
01181 // Areca RAID Controller(SAS Device)
01182 freebsd_areca_scsi_device::freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
01183 : smart_device(intf, dev_name, "areca", "areca"),
01184   freebsd_smart_device()
01185 {
01186   set_disknum(disknum);
01187   set_encnum(encnum);
01188   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
01189 }
01190 
01191 smart_device * freebsd_areca_scsi_device::autodetect_open()
01192 {
01193   return this;
01194 }
01195 
01196 int freebsd_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
01197 {
01198   int ioctlreturn = 0;
01199 
01200   if(!is_open()) {
01201       if(!open()){
01202       }
01203   }
01204   ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp);
01205   if (ioctlreturn)
01206   {
01207     // errors found
01208     return -1;
01209   }
01210 
01211   return ioctlreturn;
01212 }
01213 
01214 bool freebsd_areca_scsi_device::arcmsr_lock()
01215 {
01216   return true;
01217 }
01218 
01219 
01220 bool freebsd_areca_scsi_device::arcmsr_unlock()
01221 {
01222   return true;
01223 }
01224 
01225 
01226 /////////////////////////////////////////////////////////////////////////////
01227 /// Implement CCISS RAID support with old functions
01228 
01229 class freebsd_cciss_device
01230 : public /*implements*/ scsi_device,
01231   public /*extends*/ freebsd_smart_device
01232 {
01233 public:
01234   freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
01235 
01236   virtual bool scsi_pass_through(scsi_cmnd_io * iop);
01237   virtual bool open();
01238 
01239 private:
01240   unsigned char m_disknum; ///< Disk number.
01241 };
01242 
01243 bool freebsd_cciss_device::open()
01244 {
01245   const char *dev = get_dev_name();
01246   int fd;
01247   if ((fd = ::open(dev,O_RDWR))<0) {
01248     set_err(errno);
01249     return false;
01250   }
01251   set_fd(fd);
01252   return true;
01253 }
01254 
01255 freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
01256   const char * dev_name, unsigned char disknum)
01257 : smart_device(intf, dev_name, "cciss", "cciss"),
01258   freebsd_smart_device(),
01259   m_disknum(disknum)
01260 {
01261   set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
01262 }
01263 
01264 bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
01265 {
01266   int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
01267   if (status < 0)
01268       return set_err(-status);
01269   return true;
01270   // not reached
01271   return true;
01272 }
01273 
01274 
01275 /////////////////////////////////////////////////////////////////////////////
01276 /// SCSI open with autodetection support
01277 
01278 smart_device * freebsd_scsi_device::autodetect_open()
01279 {
01280   // Open device
01281   if (!open())
01282     return this;
01283 
01284   // No Autodetection if device type was specified by user
01285   if (*get_req_type())
01286     return this;
01287 
01288   // The code below is based on smartd.cpp:SCSIFilterKnown()
01289 
01290   // Get INQUIRY
01291   unsigned char req_buff[64] = {0, };
01292   int req_len = 36;
01293   if (scsiStdInquiry(this, req_buff, req_len)) {
01294     // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
01295     // watch this spot ... other devices could lock up here
01296     req_len = 64;
01297     if (scsiStdInquiry(this, req_buff, req_len)) {
01298       // device doesn't like INQUIRY commands
01299       close();
01300       set_err(EIO, "INQUIRY failed");
01301       return this;
01302     }
01303   }
01304 
01305   int avail_len = req_buff[4] + 5;
01306   int len = (avail_len < req_len ? avail_len : req_len);
01307   if (len < 36)
01308     return this;
01309 
01310   // Use INQUIRY to detect type
01311 
01312   // 3ware ?
01313   if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4) ||
01314       !strcmp("tws",m_camdev->sim_name) || !strcmp("twa",m_camdev->sim_name)) {
01315     close();
01316     set_err(EINVAL, "3ware/LSI controller, please try adding '-d 3ware,N',\n"
01317                     "you may need to replace %s with /dev/twaN, /dev/tweN or /dev/twsN", get_dev_name());
01318     return this;
01319   }
01320 
01321   // SAT or USB, skip MFI controllers because of bugs
01322   {
01323     smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
01324     if (newdev) {
01325       // NOTE: 'this' is now owned by '*newdev'
01326       if(!strcmp("mfi",m_camdev->sim_name)) {
01327         newdev->close();
01328         newdev->set_err(ENOSYS, "SATA device detected,\n"
01329           "MegaRAID SAT layer is reportedly buggy, use '-d sat' to try anyhow");
01330       }
01331       return newdev;
01332     }
01333   }
01334 
01335   // Nothing special found
01336   return this;
01337 }
01338 
01339 
01340 /////////////////////////////////////////////////////////////////////////////
01341 /// Implement platform interface with old functions.
01342 
01343 class freebsd_smart_interface
01344 : public /*implements*/ smart_interface
01345 {
01346 public:
01347   virtual std::string get_os_version_str();
01348 
01349   virtual std::string get_app_examples(const char * appname);
01350 
01351   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
01352     const char * pattern = 0);
01353 
01354 protected:
01355   virtual ata_device * get_ata_device(const char * name, const char * type);
01356 
01357 #if FREEBSDVER > 800100
01358   virtual ata_device * get_atacam_device(const char * name, const char * type);
01359 #endif
01360 
01361   virtual scsi_device * get_scsi_device(const char * name, const char * type);
01362 
01363   virtual smart_device * autodetect_smart_device(const char * name);
01364 
01365   virtual smart_device * get_custom_smart_device(const char * name, const char * type);
01366 
01367   virtual std::string get_valid_custom_dev_types_str();
01368 };
01369 
01370 
01371 //////////////////////////////////////////////////////////////////////
01372 
01373 std::string freebsd_smart_interface::get_os_version_str()
01374 {
01375   struct utsname osname;
01376   uname(&osname);
01377   return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
01378 }
01379 
01380 std::string freebsd_smart_interface::get_app_examples(const char * appname)
01381 {
01382   if (!strcmp(appname, "smartctl"))
01383     return smartctl_examples;
01384   return "";
01385 }
01386 
01387 ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
01388 {
01389   return new freebsd_ata_device(this, name, type);
01390 }
01391 
01392 #if FREEBSDVER > 800100
01393 ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type)
01394 {
01395   return new freebsd_atacam_device(this, name, type);
01396 }
01397 #endif
01398 
01399 scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
01400 {
01401   return new freebsd_scsi_device(this, name, type);
01402 }
01403 
01404 // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
01405 // devices on system despite of it's names
01406 //
01407 // If any errors occur, leave errno set as it was returned by the
01408 // system call, and return <0.
01409 //
01410 // arguments: 
01411 // names: resulting array
01412 // show_all - export duplicate device name or not
01413 //
01414 // Return values:
01415 // -1:   error
01416 // >=0: number of discovered devices
01417 
01418 bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
01419 {
01420   int fd;
01421   if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
01422     if (errno == ENOENT) /* There are no CAM device on this computer */
01423       return 0;
01424     int serrno = errno;
01425     pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
01426     errno = serrno;
01427     return false;
01428   }
01429 
01430   union ccb ccb;
01431   bzero(&ccb, sizeof(union ccb));
01432 
01433   ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
01434   ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
01435   ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
01436 
01437   ccb.ccb_h.func_code = XPT_DEV_MATCH;
01438   int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
01439   ccb.cdm.match_buf_len = bufsize;
01440   // TODO: Use local buffer instead of malloc() if possible
01441   ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
01442   bzero(ccb.cdm.matches,bufsize); // clear ccb.cdm.matches structure
01443   
01444   if (ccb.cdm.matches == NULL) {
01445     close(fd);
01446     throw std::bad_alloc();
01447   }
01448   ccb.cdm.num_matches = 0;
01449   ccb.cdm.num_patterns = 0;
01450   ccb.cdm.pattern_buf_len = 0;
01451 
01452   /*
01453    * We do the ioctl multiple times if necessary, in case there are
01454    * more than MAX_NUM_DEV nodes in the EDT.
01455    */
01456   int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool
01457   std::string devname;
01458   do {
01459     if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
01460       int serrno = errno;
01461       pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
01462       free(ccb.cdm.matches);
01463       close(fd);
01464       errno = serrno;
01465       return false;
01466     }
01467 
01468     if ((ccb.ccb_h.status != CAM_REQ_CMP)
01469       || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
01470       && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
01471       pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
01472       free(ccb.cdm.matches);
01473       close(fd);
01474       errno = ENXIO;
01475       return false;
01476     }
01477 
01478     for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
01479       struct bus_match_result *bus_result;
01480       struct device_match_result *dev_result;
01481       struct periph_match_result *periph_result;
01482 
01483       if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
01484         bus_result = &ccb.cdm.matches[i].result.bus_result;
01485 
01486         if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
01487         skip_bus = 1;
01488         else
01489           skip_bus = 0;
01490         changed = 1;
01491       } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
01492         dev_result = &ccb.cdm.matches[i].result.device_result;
01493 
01494         if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
01495           skip_device = 1;
01496         else
01497           skip_device = 0;
01498         
01499         //        /* Shall we skip non T_DIRECT devices ? */
01500         //        if (dev_result->inq_data.device != T_DIRECT)
01501         //          skip_device = 1;
01502         changed = 1;
01503       } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && 
01504           (skip_device == 0 || show_all)) { 
01505         /* One device may be populated as many peripherals (pass0 & da0 for example). 
01506         * We are searching for best name
01507         */
01508         periph_result =  &ccb.cdm.matches[i].result.periph_result;
01509         /* Prefer non-"pass" names */
01510         if (devname.empty() || strncmp(periph_result->periph_name, "pass", 4) != 0) {
01511           devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
01512             }
01513         changed = 0;
01514       };
01515       if ((changed == 1 || show_all) && !devname.empty()) {
01516         names.push_back(devname);
01517         devname.erase();
01518         changed = 0;
01519       };
01520     }
01521 
01522   } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
01523 
01524   if (!devname.empty())
01525     names.push_back(devname);
01526 
01527   free(ccb.cdm.matches);
01528   close(fd);
01529   return true;
01530 }
01531 
01532 // we are using ATA subsystem enumerator to found all ATA devices on system
01533 // despite of it's names
01534 //
01535 // If any errors occur, leave errno set as it was returned by the
01536 // system call, and return <0.
01537 
01538 // Return values:
01539 // -1:   error
01540 // >=0: number of discovered devices
01541 int get_dev_names_ata(char*** names) {
01542   struct ata_ioc_devices devices;
01543   int fd=-1,maxchannel,serrno=-1,n=0;
01544   char **mp = NULL;
01545 
01546   *names=NULL;
01547 
01548   if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
01549     if (errno == ENOENT) /* There are no ATA device on this computer */
01550       return 0;
01551     serrno = errno;
01552     pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
01553     n = -1;
01554     goto end;
01555   };
01556 
01557   if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
01558     serrno = errno;
01559     pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
01560     n = -1;
01561     goto end;
01562   };
01563 
01564   // allocate space for up to MAX_NUM_DEV number of ATA devices
01565   mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
01566   if (mp == NULL) {
01567     serrno=errno;
01568     pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
01569     n = -1;
01570     goto end;
01571   };
01572 
01573   for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
01574     int j;
01575 
01576     if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
01577       if (errno == ENXIO)
01578         continue; /* such channel not exist */
01579       pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
01580       n = -1;
01581       goto end;
01582     };
01583     for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
01584       if (devices.name[j][0] != '\0') {
01585         asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
01586         if (mp[n] == NULL) {
01587           pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
01588           n = -1;
01589           goto end;
01590         };
01591         bytes+=1+strlen(mp[n]);
01592         n++;
01593       };
01594     };
01595   };  
01596   mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
01597   if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL
01598     serrno=errno;
01599     pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
01600     n = -1;
01601     goto end;
01602   };
01603   bytes += (n)*(sizeof(char*)); // and set allocated byte count
01604 
01605 end:
01606   if (fd>=0)
01607     close(fd);
01608   if (n <= 0) {
01609     free(mp);
01610     mp = NULL;
01611   }
01612 
01613   *names=mp;
01614 
01615   if (serrno>-1)
01616     errno=serrno;
01617   return n;
01618 }
01619 
01620 
01621 
01622 bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
01623   const char * type, const char * pattern /*= 0*/)
01624 {
01625   if (pattern) {
01626     set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
01627     return false;
01628   }
01629 
01630   // Make namelists
01631   char * * atanames = 0; int numata = 0;
01632   if (!type || !strcmp(type, "ata")) {
01633     numata = get_dev_names_ata(&atanames);
01634     if (numata < 0) {
01635       set_err(ENOMEM);
01636       return false;
01637     }
01638   }
01639 
01640   std::vector<std::string> scsinames;
01641   if (!type || !strcmp(type, "scsi")) { // do not export duplicated names
01642     if (!get_dev_names_cam(scsinames, false)) {
01643       set_err(errno);
01644       return false;
01645     }
01646   }
01647 
01648   // Add to devlist
01649   int i;
01650   if (type==NULL)
01651     type="";
01652   for (i = 0; i < numata; i++) {
01653     ata_device * atadev = get_ata_device(atanames[i], type);
01654     if (atadev)
01655       devlist.push_back(atadev);
01656     free(atanames[i]);
01657   }
01658   if(numata) free(atanames);
01659 
01660   for (i = 0; i < (int)scsinames.size(); i++) {
01661     if(!*type) { // try USB autodetection if no type specified
01662       smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str());
01663       if(smartdev)
01664         devlist.push_back(smartdev);
01665     }
01666     else {
01667       scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type);
01668       if (scsidev)
01669         devlist.push_back(scsidev);
01670     }
01671   }
01672   return true;
01673 }
01674 
01675 
01676 #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
01677 static char done[USB_MAX_DEVICES];
01678 
01679 static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
01680   unsigned short & product_id, unsigned short & version)
01681 { 
01682 
01683   struct usb_device_info di;
01684   int e, p, i;
01685   char devname[256];
01686 
01687   snprintf(devname, sizeof(devname),"umass%d",busno);
01688 
01689   di.udi_addr = a;
01690   e = ioctl(f, USB_DEVICEINFO, &di);
01691   if (e) {
01692     if (errno != ENXIO)
01693       printf("addr %d: I/O error\n", a);
01694     return 0;
01695   }
01696   done[a] = 1;
01697 
01698   // list devices
01699   for (i = 0; i < USB_MAX_DEVNAMES; i++) {
01700     if (di.udi_devnames[i][0]) {
01701       if(strcmp(di.udi_devnames[i],devname)==0) {
01702         // device found!
01703         vendor_id = di.udi_vendorNo;
01704         product_id = di.udi_productNo;
01705         version = di.udi_releaseNo;
01706         return 1;
01707         // FIXME
01708       }
01709     }
01710   }
01711   if (!rec)
01712     return 0;
01713   for (p = 0; p < di.udi_nports; p++) {
01714     int s = di.udi_ports[p];
01715     if (s >= USB_MAX_DEVICES) {
01716       continue;
01717     }
01718     if (s == 0)
01719       printf("addr 0 should never happen!\n");
01720     else {
01721       if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
01722     }
01723   }
01724   return 0;
01725 }
01726 #endif
01727 
01728 
01729 static int usbdevlist(int busno,unsigned short & vendor_id,
01730   unsigned short & product_id, unsigned short & version)
01731 {
01732 #if (FREEBSDVER >= 800000) // libusb2 interface
01733   struct libusb20_device *pdev = NULL;
01734   struct libusb20_backend *pbe;
01735   uint32_t matches = 0;
01736   char buf[128]; // do not change!
01737   char devname[128];
01738   uint8_t n;
01739   struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
01740 
01741   pbe = libusb20_be_alloc_default();
01742 
01743   while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
01744     matches++;
01745 
01746     if (libusb20_dev_open(pdev, 0)) {
01747       warnx("libusb20_dev_open: could not open device");
01748       return 0;
01749     }
01750 
01751     pdesc=libusb20_dev_get_device_desc(pdev);
01752 
01753     snprintf(devname, sizeof(devname),"umass%d:",busno);
01754     for (n = 0; n != 255; n++) {
01755       if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
01756         break;
01757       if (buf[0] == 0)
01758         continue;
01759       if(strncmp(buf,devname,strlen(devname))==0){
01760         // found!
01761         vendor_id = pdesc->idVendor;
01762         product_id = pdesc->idProduct;
01763         version = pdesc->bcdDevice;
01764         libusb20_dev_close(pdev);
01765         libusb20_be_free(pbe);
01766         return 1;
01767       }
01768     }
01769 
01770     libusb20_dev_close(pdev);
01771   }
01772 
01773   if (matches == 0) {
01774     printf("No device match or lack of permissions.\n");
01775   }
01776 
01777   libusb20_be_free(pbe);
01778 
01779   return false;
01780 #else // freebsd < 8.0 USB stack, ioctl interface
01781 
01782   int  i, f, a, rc;
01783   char buf[50];
01784   int ncont;
01785 
01786   for (ncont = 0, i = 0; i < 10; i++) {
01787     snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
01788     f = open(buf, O_RDONLY);
01789     if (f >= 0) {
01790       memset(done, 0, sizeof done);
01791       for (a = 1; a < USB_MAX_DEVICES; a++) {
01792         if (!done[a]) {
01793           rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
01794           if(rc) return 1;
01795         }
01796 
01797       }
01798       close(f);
01799     } else {
01800       if (errno == ENOENT || errno == ENXIO)
01801         continue;
01802       warn("%s", buf);
01803     }
01804     ncont++;
01805   }
01806   return 0;
01807 #endif
01808 }
01809 
01810 smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
01811 {
01812   unsigned short vendor_id = 0, product_id = 0, version = 0;
01813   struct cam_device *cam_dev;
01814   union ccb ccb;
01815   int bus=-1;
01816   int i,c;
01817   int len;
01818   const char * test_name = name;
01819 
01820   // if dev_name null, or string length zero
01821   if (!name || !(len = strlen(name)))
01822     return 0;
01823 
01824   // Dereference symlinks
01825   struct stat st;
01826   std::string pathbuf;
01827   if (!lstat(name, &st) && S_ISLNK(st.st_mode)) {
01828     char * p = realpath(name, (char *)0);
01829     if (p) {
01830       pathbuf = p;
01831       free(p);
01832       test_name = pathbuf.c_str();
01833     }
01834   }
01835 
01836   // check ATA bus
01837   char * * atanames = 0; int numata = 0;
01838   numata = get_dev_names_ata(&atanames);
01839   if (numata > 0) {
01840     // check ATA/ATAPI devices
01841     for (i = 0; i < numata; i++) {
01842       if(!strcmp(atanames[i],test_name)) {
01843         for (c = i; c < numata; c++) free(atanames[c]);
01844         free(atanames);
01845         return new freebsd_ata_device(this, test_name, "");
01846       }
01847       else free(atanames[i]);
01848     }
01849     if(numata) free(atanames);
01850   }
01851   else {
01852     if (numata < 0)
01853       pout("Unable to get ATA device list\n");
01854   }
01855 
01856   // check CAM
01857   std::vector<std::string> scsinames;
01858   if (!get_dev_names_cam(scsinames, true))
01859     pout("Unable to get CAM device list\n");
01860   else if (!scsinames.empty()) {
01861     // check all devices on CAM bus
01862     for (i = 0; i < (int)scsinames.size(); i++) {
01863       if(strcmp(scsinames[i].c_str(), test_name)==0)
01864       { // our disk device is CAM
01865         if(strncmp(scsinames[i].c_str(), "/dev/pmp", strlen("/dev/pmp")) == 0) {
01866           pout("Skipping port multiplier [%s]\n", scsinames[i].c_str());
01867           set_err(EINVAL);
01868           return 0;
01869         }
01870         if ((cam_dev = cam_open_device(test_name, O_RDWR)) == NULL) {
01871           // open failure
01872           set_err(errno);
01873           return 0;
01874         }
01875         // zero the payload
01876         bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE);
01877         ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device
01878         if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
01879           warn("Get Transfer Settings CCB failed\n"
01880             "%s", strerror(errno));
01881           cam_close_device(cam_dev);
01882           return 0;
01883         }
01884         // now check if we are working with USB device, see umass.c
01885         if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found
01886           usbdevlist(bus,vendor_id, product_id, version);
01887           int bus=ccb.cpi.unit_number; // unit_number will match umass number
01888           cam_close_device(cam_dev);
01889           if(usbdevlist(bus,vendor_id, product_id, version)){
01890             const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
01891             if (usbtype)
01892               return get_sat_device(usbtype, new freebsd_scsi_device(this, test_name, ""));
01893           }
01894           return 0;
01895         }
01896 #if FREEBSDVER > 800100
01897         // check if we have ATA device connected to CAM (ada)
01898         if(ccb.cpi.protocol == PROTO_ATA){
01899           cam_close_device(cam_dev);
01900           return new freebsd_atacam_device(this, test_name, "");
01901         }
01902 #endif
01903         // close cam device, we don`t need it anymore
01904         cam_close_device(cam_dev);
01905         // handle as usual scsi
01906         return new freebsd_scsi_device(this, test_name, "");      
01907       }
01908     }
01909   }
01910   // device is LSI raid supported by mfi driver
01911   if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid")))
01912     set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information");
01913   // device type unknown
01914   return 0;
01915 }
01916 
01917 
01918 smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
01919 {
01920   // 3Ware ?
01921   static const char * fbsd_dev_twe_ctrl = "/dev/twe";
01922   static const char * fbsd_dev_twa_ctrl = "/dev/twa";
01923   static const char * fbsd_dev_tws_ctrl = "/dev/tws";
01924   int disknum = -1, n1 = -1, n2 = -1, contr = -1;
01925 
01926   if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
01927     if (n2 != (int)strlen(type)) {
01928       set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
01929       return 0;
01930     }
01931     if (!(0 <= disknum && disknum <= 127)) {
01932       set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
01933       return 0;
01934     }
01935 
01936     // guess 3ware device type based on device name
01937     if (str_starts_with(name, fbsd_dev_twa_ctrl) ||
01938         str_starts_with(name, fbsd_dev_tws_ctrl)   ) {
01939       contr=CONTROLLER_3WARE_9000_CHAR;
01940     }
01941     if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){
01942       contr=CONTROLLER_3WARE_678K_CHAR;
01943     }
01944 
01945     if(contr == -1){
01946       set_err(EINVAL, "3ware controller type unknown, use %sX, %sX or %sX devices", 
01947         fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl, fbsd_dev_tws_ctrl);
01948       return 0;
01949     }
01950     return new freebsd_escalade_device(this, name, contr, disknum);
01951   }
01952 
01953   // Highpoint ?
01954   int controller = -1, channel = -1; disknum = 1;
01955   n1 = n2 = -1; int n3 = -1;
01956   if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
01957     int len = strlen(type);
01958     if (!(n2 == len || n3 == len)) {
01959       set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
01960       return 0;
01961     }
01962     if (!(1 <= controller && controller <= 8)) {
01963       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
01964       return 0;
01965     }
01966     if (!(1 <= channel && channel <= 128)) {
01967       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
01968       return 0;
01969     }
01970     if (!(1 <= disknum && disknum <= 15)) {
01971       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
01972       return 0;
01973     }
01974     return new freebsd_highpoint_device(this, name, controller, channel, disknum);
01975   }
01976 
01977   // CCISS ?
01978   disknum = n1 = n2 = -1;
01979   if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
01980     if (n2 != (int)strlen(type)) {
01981       set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
01982       return 0;
01983     }
01984     if (!(0 <= disknum && disknum <= 127)) {
01985       set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
01986       return 0;
01987     }
01988     return get_sat_device("sat,auto", new freebsd_cciss_device(this, name, disknum));
01989   }
01990 #if FREEBSDVER > 800100
01991   // adaX devices ?
01992   if(!strcmp(type,"atacam"))
01993     return new freebsd_atacam_device(this, name, "");
01994 #endif
01995   // Areca?
01996   disknum = n1 = n2 = -1;
01997   int encnum = 1;
01998   if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
01999     if (!(1 <= disknum && disknum <= 128)) {
02000       set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
02001       return 0;
02002     }
02003     if (!(1 <= encnum && encnum <= 8)) {
02004       set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
02005       return 0;
02006     }
02007     return new freebsd_areca_ata_device(this, name, disknum, encnum);
02008   }
02009 
02010   return 0;
02011 }
02012 
02013 std::string freebsd_smart_interface::get_valid_custom_dev_types_str()
02014 {
02015   return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E"
02016 #if FREEBSDVER > 800100
02017   ", atacam"
02018 #endif
02019   ;
02020 }
02021 
02022 } // namespace
02023 
02024 /////////////////////////////////////////////////////////////////////////////
02025 /// Initialize platform interface and register with smi()
02026 
02027 void smart_interface::init()
02028 {
02029   static os_freebsd::freebsd_smart_interface the_interface;
02030   smart_interface::set(&the_interface);
02031 }