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