Ticket #2: smartnew.diff

File smartnew.diff, 73.5 KB (added by Alex Samorukov, 15 years ago)

patch fo the os_freebsd.cpp

  • os_freebsd.cpp

     
    2323#include <camlib.h>
    2424#include <cam/scsi/scsi_message.h>
    2525#include <cam/scsi/scsi_pass.h>
     26#include <dev/usb/usb.h>
    2627#if defined(__DragonFly__)
    2728#include <sys/nata.h>
    2829#else
     
    3031#endif
    3132#include <sys/stat.h>
    3233#include <unistd.h>
    33 #include <fcntl.h>
    3434#include <glob.h>
    35 #include <fcntl.h>
    3635#include <stddef.h>
    3736#include <paths.h>
     37#include <sys/utsname.h>
    3838
    39 
    4039#include "config.h"
    4140#include "int64.h"
    4241#include "atacmds.h"
     
    4645#include "extern.h"
    4746#include "os_freebsd.h"
    4847
     48#include "dev_interface.h"
     49#include "dev_ata_cmd_set.h"
     50
     51#define USBDEV "/dev/usb"
     52
     53#define CONTROLLER_UNKNOWN              0x00
     54#define CONTROLLER_ATA                  0x01
     55#define CONTROLLER_SCSI                 0x02
     56#define CONTROLLER_3WARE                0x03  // set by -d option, but converted to one of three types below
     57#define CONTROLLER_3WARE_678K           0x04  // NOT set by guess_device_type()
     58#define CONTROLLER_3WARE_9000_CHAR      0x05  // set by guess_device_type()
     59#define CONTROLLER_3WARE_678K_CHAR      0x06  // set by guess_device_type()
     60#define CONTROLLER_MARVELL_SATA         0x07  // SATA drives behind Marvell controllers
     61#define CONTROLLER_SAT                  0x08  // SATA device behind a SCSI ATA Translation (SAT) layer
     62#define CONTROLLER_HPT                  0x09  // SATA drives behind HighPoint Raid controllers
     63#define CONTROLLER_CCISS                0x10  // CCISS controller
     64#define CONTROLLER_PARSEDEV             0x11  // "smartctl -r ataioctl,2 ..." output parser pseudo-device
     65#define CONTROLLER_USBCYPRESS           0x12  // ATA device behind Cypress USB bridge
     66#define CONTROLLER_ARECA                0x13  // Areca controller
     67
    4968static __unused const char *filenameandversion="$Id: os_freebsd.cpp,v 1.73 2009/01/14 02:39:00 sxzzsf Exp $";
    5069
    5170const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp,v 1.73 2009/01/14 02:39:00 sxzzsf Exp $" \
     
    5877struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV];
    5978
    6079// forward declaration
    61 static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *ch);
     80// static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *ch);
    6281
    63 // print examples for smartctl
    64 void print_smartctl_examples(){
    65   printf("=================================================== SMARTCTL EXAMPLES =====\n\n");
    66 #ifdef HAVE_GETOPT_LONG
    67   printf(
     82
     83// Returns 1 if device not available/open/found else 0.  Also shifts fd into valid range.
     84static int isnotopen(int *fd, struct freebsd_dev_channel** fdchan) {
     85  // put valid "file descriptor" into range 0...FREEBSD_MAXDEV-1
     86  *fd -= FREEBSD_FDOFFSET;
     87 
     88  // check for validity of "file descriptor".
     89  if (*fd<0 || *fd>=FREEBSD_MAXDEV || !((*fdchan)=devicetable[*fd])) {
     90    errno = ENODEV;
     91    return 1;
     92  }
     93 
     94  return 0;
     95}
     96
     97#define NO_RETURN 0
     98#define BAD_SMART 1
     99#define NO_DISK_3WARE 2
     100#define BAD_KERNEL 3
     101#define MAX_MSG 3
     102
     103// Utility function for printing warnings
     104void printwarning(int msgNo, const char* extra) {
     105  static int printed[] = {0,0,0,0};
     106  static const char* message[]={
     107    "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",
     108   
     109    "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
     110   
     111    "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
     112   
     113    "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
     114  };
     115
     116  if (msgNo >= 0 && msgNo <= MAX_MSG) {
     117    if (!printed[msgNo]) {
     118      printed[msgNo] = 1;
     119      pout("%s", message[msgNo]);
     120      if (extra)
     121        pout("%s",extra);
     122    }
     123  }
     124  return;
     125}
     126
     127
     128// Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
     129
     130#define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
     131#define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
     132#define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
     133
     134
     135
     136
     137
     138
     139#ifndef ATA_DEVICE
     140#define ATA_DEVICE "/dev/ata"
     141#endif
     142
     143
     144
     145// global variable holding byte count of allocated memory
     146long long bytes;
     147
     148
     149/*
     150 * dev_legacy.cpp
     151 *
     152 * Home page of code is: http://smartmontools.sourceforge.net
     153 *
     154 * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
     155 *
     156 * This program is free software; you can redistribute it and/or modify
     157 * it under the terms of the GNU General Public License as published by
     158 * the Free Software Foundation; either version 2, or (at your option)
     159 * any later version.
     160 *
     161 * You should have received a copy of the GNU General Public License
     162 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
     163 *
     164 */
     165
     166
     167const char * dev_freebsd_cpp_cvsid = "$Id: dev_legacy.cpp,v 1.2 2008/12/18 03:40:05 dlukes Exp $"
     168  DEV_INTERFACE_H_CVSID;
     169
     170extern smartmonctrl * con; // con->reportscsiioctl
     171
     172/////////////////////////////////////////////////////////////////////////////
     173
     174#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
     175int ata_identify_is_cached(int fd);
     176#endif
     177
     178/////////////////////////////////////////////////////////////////////////////
     179
     180namespace os_freebsd { // No need to publish anything, name provided for Doxygen
     181
     182/////////////////////////////////////////////////////////////////////////////
     183/// Implement shared open/close routines with old functions.
     184
     185class freebsd_smart_device
     186: virtual public /*implements*/ smart_device
     187{
     188public:
     189  explicit freebsd_smart_device(const char * mode)
     190    : smart_device(never_called),
     191      m_fd(-1), m_mode(mode) { }
     192
     193  virtual ~freebsd_smart_device() throw();
     194
     195  virtual bool is_open() const;
     196
     197  virtual bool open();
     198
     199  virtual bool close();
     200
     201protected:
     202  /// Return filedesc for derived classes.
     203  int get_fd() const
     204    { return m_fd; }
     205
     206private:
     207  int m_fd; ///< filedesc, -1 if not open.
     208  const char * m_mode; ///< Mode string for deviceopen().
     209};
     210
     211
     212freebsd_smart_device::~freebsd_smart_device() throw()
     213{
     214  if (m_fd >= 0)
     215    os_freebsd::freebsd_smart_device::close();
     216}
     217
     218// migration from the old_style
     219unsigned char m_controller_type;
     220unsigned char m_controller_port;
     221
     222// examples for smartctl
     223static const char  smartctl_examples[] =
     224        "=================================================== SMARTCTL EXAMPLES =====\n\n"
    68225         "  smartctl -a /dev/ad0                       (Prints all SMART information)\n\n"
    69226         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
    70227         "                                              (Enables SMART on first disk)\n\n"
     
    76233         "  smartctl -a --device=3ware,2 /dev/twe0\n"
    77234         "                              (Prints all SMART information for ATA disk on\n"
    78235         "                                 third port of first 3ware RAID controller)\n"
    79          );
     236         ;
     237
     238bool freebsd_smart_device::is_open() const
     239{
     240  return (m_fd >= 0);
     241}
     242
     243
     244static int hpt_hba(const char* name) {
     245  int i=0;
     246  const char *hpt_node[]={"hptmv", "hptmv6", "hptrr", "hptiop", "hptmviop", "hpt32xx", "rr2320",
     247                          "rr232x", "rr2310", "rr2310_00", "rr2300", "rr2340", "rr1740", NULL};
     248  while (hpt_node[i]) {
     249    if (!strncmp(name, hpt_node[i], strlen(hpt_node[i])))
     250      return 1;
     251    i++;
     252  }
     253  return 0;
     254}
     255
     256static int get_tw_channel_unit (const char* name, int* unit, int* dev) {
     257  const char *p;
     258
     259  /* device node sanity check */
     260  for (p = name + 3; *p; p++)
     261    if (*p < '0' || *p > '9')
     262      return -1;
     263  if (strlen(name) > 4 && *(name + 3) == '0')
     264    return -1;
     265
     266  if (dev != NULL)
     267    *dev=atoi(name + 3);
     268
     269  /* no need for unit number */
     270  if (unit != NULL)
     271    *unit=0;
     272  return 0;
     273}
     274
     275#ifndef IOCATAREQUEST
     276static int get_ata_channel_unit ( const char* name, int* unit, int* dev) {
     277#ifndef ATAREQUEST
     278  *dev=0;
     279  *unit=0;
     280return 0;
    80281#else
    81   printf(
    82          "  smartctl -a /dev/ad0                       (Prints all SMART information)\n"
    83          "  smartctl -s on -o on -S on /dev/ad0         (Enables SMART on first disk)\n"
    84          "  smartctl -t long /dev/ad0              (Executes extended disk self-test)\n"
    85          "  smartctl -A -l selftest -q errorsonly /dev/ad0\n"
    86          "                                      (Prints Self-Test & Attribute errors)\n"
    87          "  smartctl -a -d 3ware,2 /dev/twa0\n"
    88          "  smartctl -a -d 3ware,2 /dev/twe0\n"
    89          );
     282  // there is no direct correlation between name 'ad0, ad1, ...' and
     283  // channel/unit number.  So we need to iterate through the possible
     284  // channels and check each unit to see if we match names
     285  struct ata_cmd iocmd;
     286  int fd,maxunit;
     287 
     288  bzero(&iocmd, sizeof(struct ata_cmd));
     289
     290  if ((fd = open(ATA_DEVICE, O_RDWR)) < 0)
     291    return -errno;
     292 
     293  iocmd.cmd = ATAGMAXCHANNEL;
     294  if (ioctl(fd, IOCATA, &iocmd) < 0) {
     295    return -errno;
     296    close(fd);
     297  }
     298  maxunit = iocmd.u.maxchan;
     299  for (*unit = 0; *unit < maxunit; (*unit)++) {
     300    iocmd.channel = *unit;
     301    iocmd.device = -1;
     302    iocmd.cmd = ATAGPARM;
     303    if (ioctl(fd, IOCATA, &iocmd) < 0) {
     304      close(fd);
     305      return -errno;
     306    }
     307    if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) {
     308      *dev = 0;
     309      break;
     310    }
     311    if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) {
     312      *dev = 1;
     313      break;
     314    }
     315  }
     316  close(fd);
     317  if (*unit == maxunit)
     318    return -1;
     319  else
     320    return 0;
    90321#endif
    91   return;
    92322}
     323#endif
    93324
    94 // Like open().  Return positive integer handle, used by functions below only.
    95 int deviceopen (const char* dev, __unused char* mode) {
     325// Guess device type (ata or scsi) based on device name (FreeBSD
     326// specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst,
     327// osst, nosst and sg.
     328static const char * fbsd_dev_prefix = _PATH_DEV;
     329static const char * fbsd_dev_ata_disk_prefix = "ad";
     330static const char * fbsd_dev_scsi_disk_plus = "da";
     331static const char * fbsd_dev_scsi_pass = "pass";
     332static const char * fbsd_dev_scsi_tape1 = "sa";
     333static const char * fbsd_dev_scsi_tape2 = "nsa";
     334static const char * fbsd_dev_scsi_tape3 = "esa";
     335static const char * fbsd_dev_twe_ctrl = "twe";
     336static const char * fbsd_dev_twa_ctrl = "twa";
     337static const char * fbsd_dev_cciss = "ciss";
     338
     339int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) {
     340  int len;
     341  int dev_prefix_len = strlen(fbsd_dev_prefix);
     342 
     343  // if dev_name null, or string length zero
     344  if (!dev_name || !(len = strlen(dev_name)))
     345    return CONTROLLER_UNKNOWN;
     346 
     347  // Remove the leading /dev/... if it's there
     348  if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) {
     349    if (len <= dev_prefix_len)
     350      // if nothing else in the string, unrecognized
     351      return CONTROLLER_UNKNOWN;
     352    // else advance pointer to following characters
     353    dev_name += dev_prefix_len;
     354  }
     355  // form /dev/ad* or ad*
     356  if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name,
     357               strlen(fbsd_dev_ata_disk_prefix))) {
     358#ifndef IOCATAREQUEST
     359    if (chan != NULL) {
     360      if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
     361        return CONTROLLER_UNKNOWN;
     362      }
     363    }
     364#endif
     365    return CONTROLLER_ATA;
     366  }
     367
     368  // form /dev/pass* or pass*
     369  if (!strncmp(fbsd_dev_scsi_pass, dev_name,
     370               strlen(fbsd_dev_scsi_pass)))
     371    goto handlescsi;
     372
     373  // form /dev/da* or da*
     374  if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name,
     375               strlen(fbsd_dev_scsi_disk_plus)))
     376    goto handlescsi;
     377
     378  // form /dev/sa* or sa*
     379  if (!strncmp(fbsd_dev_scsi_tape1, dev_name,
     380              strlen(fbsd_dev_scsi_tape1)))
     381    goto handlescsi;
     382
     383  // form /dev/nsa* or nsa*
     384  if (!strncmp(fbsd_dev_scsi_tape2, dev_name,
     385              strlen(fbsd_dev_scsi_tape2)))
     386    goto handlescsi;
     387
     388  // form /dev/esa* or esa*
     389  if (!strncmp(fbsd_dev_scsi_tape3, dev_name,
     390              strlen(fbsd_dev_scsi_tape3)))
     391    goto handlescsi;
     392 
     393  if (!strncmp(fbsd_dev_twa_ctrl,dev_name,
     394               strlen(fbsd_dev_twa_ctrl))) {
     395    if (chan != NULL) {
     396      if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
     397        return CONTROLLER_UNKNOWN;
     398      }
     399    }
     400    else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
     401        return CONTROLLER_UNKNOWN;
     402    }
     403    return CONTROLLER_3WARE_9000_CHAR;
     404  }
     405
     406  if (!strncmp(fbsd_dev_twe_ctrl,dev_name,
     407               strlen(fbsd_dev_twe_ctrl))) {
     408    if (chan != NULL) {
     409      if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
     410        return CONTROLLER_UNKNOWN;
     411      }
     412    }
     413    else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
     414        return CONTROLLER_UNKNOWN;
     415    }
     416    return CONTROLLER_3WARE_678K_CHAR;
     417  }
     418
     419  if (hpt_hba(dev_name)) {
     420    return CONTROLLER_HPT;
     421  }
     422
     423  // form /dev/ciss*
     424  if (!strncmp(fbsd_dev_cciss, dev_name,
     425               strlen(fbsd_dev_cciss)))
     426    return CONTROLLER_CCISS;
     427
     428  // we failed to recognize any of the forms
     429  return CONTROLLER_UNKNOWN;
     430
     431 handlescsi:
     432  if (chan != NULL) {
     433    if (!(chan->devname = (char *)calloc(1,DEV_IDLEN+1)))
     434      return CONTROLLER_UNKNOWN;
     435   
     436    if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1)
     437      return CONTROLLER_UNKNOWN;
     438  }
     439  return CONTROLLER_SCSI;
     440 
     441}
     442
     443
     444bool freebsd_smart_device::open()
     445{
     446       
     447  const char *dev = get_dev_name();
    96448  struct freebsd_dev_channel *fdchan;
    97449  int parse_ok, i;
    98450
     
    105457  // of "file descriptors" already allocated.
    106458  if (i == FREEBSD_MAXDEV) {
    107459    errno = EMFILE;
    108     return -1;
     460    return false;
    109461  }
    110462
    111463  fdchan = (struct freebsd_dev_channel *)calloc(1,sizeof(struct freebsd_dev_channel));
    112464  if (fdchan == NULL) {
    113465    // errno already set by call to malloc()
    114     return -1;
     466    return false;
    115467  }
    116468
    117469  parse_ok = parse_ata_chan_dev(dev,fdchan);
     470 
    118471  if (parse_ok == CONTROLLER_UNKNOWN) {
    119472    free(fdchan);
    120473    errno = ENOTTY;
    121     return -1; // can't handle what we don't know
     474    return false; // can't handle what we don't know
    122475  }
    123476
    124477  if (parse_ok == CONTROLLER_ATA) {
    125478#ifdef IOCATAREQUEST
    126     if ((fdchan->device = open(dev,O_RDONLY))<0) {
     479    if ((fdchan->device = ::open(dev,O_RDONLY))<0) {
    127480#else
    128     if ((fdchan->atacommand = open("/dev/ata",O_RDWR))<0) {
     481    if ((fdchan->atacommand = ::open("/dev/ata",O_RDWR))<0) {
    129482#endif
    130483      int myerror = errno;      // preserve across free call
    131484      free(fdchan);
    132485      errno = myerror;
    133       return -1;
     486      return false;
    134487    }
    135488  }
    136489
     
    138491    char buf[512];
    139492    sprintf(buf,"/dev/twe%d",fdchan->device);
    140493#ifdef IOCATAREQUEST
    141     if ((fdchan->device = open(buf,O_RDWR))<0) {
     494    if ((fdchan->device = ::open(buf,O_RDWR))<0) {
    142495#else
    143     if ((fdchan->atacommand = open(buf,O_RDWR))<0) {
     496    if ((fdchan->atacommand = ::open(buf,O_RDWR))<0) {
    144497#endif
    145498      int myerror = errno;      // preserve across free call
    146499      free(fdchan);
    147500      errno = myerror;
    148       return -1;
     501      return false;
    149502    }
    150503  }
    151504
     
    153506    char buf[512];
    154507    sprintf(buf,"/dev/twa%d",fdchan->device);
    155508#ifdef IOCATAREQUEST
    156     if ((fdchan->device = open(buf,O_RDWR))<0) {
     509    if ((fdchan->device = ::open(buf,O_RDWR))<0) {
    157510#else
    158     if ((fdchan->atacommand = open(buf,O_RDWR))<0) {
     511    if ((fdchan->atacommand = ::open(buf,O_RDWR))<0) {
    159512#endif
    160513      int myerror = errno;      // preserve across free call
    161514      free(fdchan);
    162515      errno = myerror;
    163       return -1;
     516      return false;
    164517    }
    165518  }
    166519
    167520  if (parse_ok == CONTROLLER_HPT) {
    168     if ((fdchan->device = open(dev,O_RDWR))<0) {
     521    if ((fdchan->device = ::open(dev,O_RDWR))<0) {
    169522      int myerror = errno;      // preserve across free call
    170523      free(fdchan);
    171524      errno = myerror;
    172       return -1;
     525      return false;
    173526    }
    174527  }
    175528
    176529  if (parse_ok == CONTROLLER_CCISS) {
    177     if ((fdchan->device = open(dev,O_RDWR))<0) {
     530    if ((fdchan->device = ::open(dev,O_RDWR))<0) {
    178531      int myerror = errno;      // preserve across free call
    179532      free(fdchan);
    180533      errno = myerror;
    181       return -1;
     534      return false;
    182535    }
    183536  }
    184537
     
    189542 
    190543  // return pointer to "file descriptor" table entry, properly offset.
    191544  devicetable[i]=fdchan;
    192   return i+FREEBSD_FDOFFSET;
    193 }
    194 
    195 // Returns 1 if device not available/open/found else 0.  Also shifts fd into valid range.
    196 static int isnotopen(int *fd, struct freebsd_dev_channel** fdchan) {
    197   // put valid "file descriptor" into range 0...FREEBSD_MAXDEV-1
    198   *fd -= FREEBSD_FDOFFSET;
    199  
    200   // check for validity of "file descriptor".
    201   if (*fd<0 || *fd>=FREEBSD_MAXDEV || !((*fdchan)=devicetable[*fd])) {
    202     errno = ENODEV;
    203     return 1;
     545  m_fd = i+FREEBSD_FDOFFSET;
     546  // endofold
     547  if (m_fd < 0) {
     548    set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
     549    return false;
    204550  }
    205  
    206   return 0;
     551  return true;
    207552}
    208553
    209 // Like close().  Acts on handles returned by above function.
    210 int deviceclose (int fd) {
     554bool freebsd_smart_device::close()
     555{
     556  int fd = m_fd; m_fd = -1;
    211557  struct freebsd_dev_channel *fdchan;
    212558  int failed = 0;
    213559
    214560  // check for valid file descriptor
    215561  if (isnotopen(&fd, &fdchan))
    216     return -1;
     562    return false;
    217563 
    218564
    219565  // did we allocate a SCSI device name?
     
    222568 
    223569  // close device, if open
    224570  if (fdchan->device)
    225     failed=close(fdchan->device);
     571    failed=::close(fdchan->device);
    226572#ifndef IOCATAREQUEST
    227573  if (fdchan->atacommand)
    228     failed=close(fdchan->atacommand);
     574    failed=::close(fdchan->atacommand);
    229575#endif
    230576 
    231577  // if close succeeded, then remove from device list
     
    239585  return failed;
    240586}
    241587
    242 #define NO_RETURN 0
    243 #define BAD_SMART 1
    244 #define NO_DISK_3WARE 2
    245 #define BAD_KERNEL 3
    246 #define MAX_MSG 3
     588/////////////////////////////////////////////////////////////////////////////
     589/// Implement standard ATA support with old functions
    247590
    248 // Utility function for printing warnings
    249 void printwarning(int msgNo, const char* extra) {
    250   static int printed[] = {0,0,0,0};
    251   static const char* message[]={
    252     "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",
     591class freebsd_ata_device
     592: public /*implements*/ ata_device_with_command_set,
     593  public /*extends*/ freebsd_smart_device
     594{
     595public:
     596  freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
     597
     598#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
     599  virtual bool ata_identify_is_cached() const;
     600#endif
     601
     602protected:
     603  virtual int ata_command_interface(smart_command_set command, int select, char * data);
     604};
     605
     606freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
     607: smart_device(intf, dev_name, "ata", req_type),
     608  freebsd_smart_device("ATA")
     609{
     610}
     611
     612int freebsd_ata_device::ata_command_interface(smart_command_set command, int select, char * data)
     613{
     614        int fd=get_fd();
     615        #if !defined(ATAREQUEST) && !defined(IOCATAREQUEST)
     616        // sorry, but without ATAng, we can't do anything here
     617        printwarning(BAD_KERNEL,NULL);
     618        errno = ENOSYS;
     619        return -1;
     620        #else
     621        struct freebsd_dev_channel* con;
     622        int retval, copydata=0;
     623        #ifdef IOCATAREQUEST
     624        struct ata_ioc_request request;
     625        #else
     626        struct ata_cmd iocmd;
     627        #endif
     628        unsigned char buff[512];
     629       
     630        // check that "file descriptor" is valid
     631        if (isnotopen(&fd,&con))
     632                return -1;
     633       
     634        bzero(buff,512);
     635       
     636        #ifdef IOCATAREQUEST
     637        bzero(&request,sizeof(struct ata_ioc_request));
     638        #else
     639        bzero(&iocmd,sizeof(struct ata_cmd));
     640        #endif
     641        bzero(buff,512);
     642       
     643        #ifndef IOCATAREQUEST
     644        iocmd.cmd=ATAREQUEST;
     645        iocmd.channel=con->channel;
     646        iocmd.device=con->device;
     647        #define request iocmd.u.request
     648        #endif
     649       
     650        request.u.ata.command=ATA_SMART_CMD;
     651        request.timeout=600;
     652        switch (command){
     653        case READ_VALUES:
     654                request.u.ata.feature=ATA_SMART_READ_VALUES;
     655                request.u.ata.lba=0xc24f<<8;
     656                request.flags=ATA_CMD_READ;
     657                request.data=(char *)buff;
     658                request.count=512;
     659                copydata=1;
     660                break;
     661        case READ_THRESHOLDS:
     662                request.u.ata.feature=ATA_SMART_READ_THRESHOLDS;
     663                request.u.ata.count=1;
     664                request.u.ata.lba=1|(0xc24f<<8);
     665                request.flags=ATA_CMD_READ;
     666                request.data=(char *)buff;
     667                request.count=512;
     668                copydata=1;
     669                break;
     670        case READ_LOG:
     671                request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR;
     672                request.u.ata.lba=select|(0xc24f<<8);
     673                request.u.ata.count=1;
     674                request.flags=ATA_CMD_READ;
     675                request.data=(char *)buff;
     676                request.count=512;
     677                copydata=1;
     678                break;
     679        case IDENTIFY:
     680                request.u.ata.command=ATA_IDENTIFY_DEVICE;
     681                request.flags=ATA_CMD_READ;
     682                request.data=(char *)buff;
     683                request.count=512;
     684                copydata=1;
     685                break;
     686        case PIDENTIFY:
     687                request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE;
     688                request.flags=ATA_CMD_READ;
     689                request.data=(char *)buff;
     690                request.count=512;
     691                copydata=1;
     692                break;
     693        case ENABLE:
     694                request.u.ata.feature=ATA_SMART_ENABLE;
     695                request.u.ata.lba=0xc24f<<8;
     696                request.flags=ATA_CMD_CONTROL;
     697                break;
     698        case DISABLE:
     699                request.u.ata.feature=ATA_SMART_DISABLE;
     700                request.u.ata.lba=0xc24f<<8;
     701                request.flags=ATA_CMD_CONTROL;
     702                break;
     703        case AUTO_OFFLINE:
     704                // NOTE: According to ATAPI 4 and UP, this command is obsolete
     705                request.u.ata.feature=ATA_SMART_AUTO_OFFLINE;
     706                request.u.ata.lba=0xc24f<<8;                                                                                                                                         
     707                request.u.ata.count=select;                                                                                                                                         
     708                request.flags=ATA_CMD_CONTROL;
     709                break;
     710        case AUTOSAVE:
     711                request.u.ata.feature=ATA_SMART_AUTOSAVE;
     712                request.u.ata.lba=0xc24f<<8;
     713                request.u.ata.count=select;
     714                request.flags=ATA_CMD_CONTROL;
     715                break;
     716        case IMMEDIATE_OFFLINE:
     717                request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE;
     718                request.u.ata.lba = select|(0xc24f<<8); // put test in sector
     719                request.flags=ATA_CMD_CONTROL;
     720                break;
     721        case STATUS_CHECK: // same command, no HDIO in FreeBSD
     722        case STATUS:
     723                // this command only says if SMART is working.  It could be
     724                // replaced with STATUS_CHECK below.
     725                request.u.ata.feature=ATA_SMART_STATUS;
     726                request.u.ata.lba=0xc24f<<8;
     727                request.flags=ATA_CMD_CONTROL;
     728                break;
     729        case CHECK_POWER_MODE:
     730                request.u.ata.command=ATA_CHECK_POWER_MODE;
     731                request.u.ata.feature=0;
     732                request.flags=ATA_CMD_CONTROL;
     733                break;
     734        case WRITE_LOG:
     735                memcpy(buff, data, 512);
     736                request.u.ata.feature=ATA_SMART_WRITE_LOG_SECTOR;
     737                request.u.ata.lba=select|(0xc24f<<8);
     738                request.u.ata.count=1;
     739                request.flags=ATA_CMD_WRITE;
     740                request.data=(char *)buff;
     741                request.count=512;
     742                break;
     743        default:
     744                pout("Unrecognized command %d in ata_command_interface()\n"
     745                        "Please contact " PACKAGE_BUGREPORT "\n", command);
     746                errno=ENOSYS;
     747                return -1;
     748        }
     749       
     750        if (command==STATUS_CHECK){
     751                unsigned const char normal_lo=0x4f, normal_hi=0xc2;
     752                unsigned const char failed_lo=0xf4, failed_hi=0x2c;
     753                unsigned char low,high;
     754               
     755                #ifdef IOCATAREQUEST
     756                if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)
     757                        #else
     758                if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
     759                        #endif
     760                return -1;
     761               
     762                #if __FreeBSD_version < 502000
     763                printwarning(NO_RETURN,NULL);
     764                #endif
     765               
     766                high = (request.u.ata.lba >> 16) & 0xff;
     767                low = (request.u.ata.lba >> 8) & 0xff;
     768               
     769                // Cyl low and Cyl high unchanged means "Good SMART status"
     770                if (low==normal_lo && high==normal_hi)
     771                        return 0;
     772               
     773                // These values mean "Bad SMART status"
     774                if (low==failed_lo && high==failed_hi)
     775                        return 1;
     776               
     777                // We haven't gotten output that makes sense; print out some debugging info
     778                char buf[512];
     779                sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
     780                        (int)request.u.ata.command,
     781                        (int)request.u.ata.feature,
     782                        (int)request.u.ata.count,
     783                        (int)((request.u.ata.lba) & 0xff),
     784                        (int)((request.u.ata.lba>>8) & 0xff),
     785                        (int)((request.u.ata.lba>>16) & 0xff),
     786                        (int)request.error);
     787                printwarning(BAD_SMART,buf);
     788                return 0;   
     789        }
     790       
     791        #ifdef IOCATAREQUEST
     792        if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)
     793                #else
     794        if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
     795                #endif
     796        {
     797                return -1;
     798        }
     799        //
     800        if (command == CHECK_POWER_MODE) {
     801                data[0] = request.u.ata.count & 0xff;
     802                return 0;
     803        }
     804        if (copydata)
     805                memcpy(data, buff, 512);
     806       
     807        return 0;
     808        #endif
     809}
     810
     811#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
     812bool freebsd_ata_device::ata_identify_is_cached() const
     813{
     814  return !!::ata_identify_is_cached(get_fd());
     815}
     816#endif
     817
     818
     819/////////////////////////////////////////////////////////////////////////////
     820/// Implement AMCC/3ware RAID support with old functions
     821
     822class freebsd_escalade_device
     823: public /*implements*/ ata_device_with_command_set,
     824  public /*extends*/ freebsd_smart_device
     825{
     826public:
     827  freebsd_escalade_device(smart_interface * intf, const char * dev_name,
     828    int escalade_type, int disknum);
     829
     830protected:
     831  virtual int ata_command_interface(smart_command_set command, int select, char * data);
     832
     833private:
     834  int m_escalade_type; ///< Type string for escalade_command_interface().
     835  int m_disknum; ///< Disk number.
     836};
     837
     838freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name,
     839    int escalade_type, int disknum)
     840: smart_device(intf, dev_name, "3ware", "3ware"),
     841  freebsd_smart_device(
     842    escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" :
     843    escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" :
     844    /*             CONTROLLER_3WARE_678K     */ "ATA"             ),
     845  m_escalade_type(escalade_type), m_disknum(disknum)
     846{
     847  set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
     848}
     849
     850int freebsd_escalade_device::ata_command_interface(smart_command_set command, int select, char * data)
     851{
     852    // to hold true file descriptor
     853    int fd = get_fd();
     854  struct freebsd_dev_channel* con;
     855
     856  // return value and buffer for ioctl()
     857  int  ioctlreturn, readdata=0;
     858  struct twe_usercommand* cmd_twe = NULL;
     859  TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
     860  TWE_Command_ATA* ata = NULL;
     861
     862  // Used by both the SCSI and char interfaces
     863  char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
     864
     865  if (m_disknum < 0) {
     866    printwarning(NO_DISK_3WARE,NULL);
     867    return -1;
     868  }
     869
     870  // check that "file descriptor" is valid
     871  if (isnotopen(&fd,&con))
     872      return -1;
     873
     874  memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
     875
     876  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
     877    cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
     878    cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
     879    cmd_twa->driver_pkt.buffer_length = 512;
     880    ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
     881  } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
     882    cmd_twe = (struct twe_usercommand*)ioctl_buffer;
     883    ata = &cmd_twe->tu_command.ata;
     884  } else {
     885    pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
     886         "Please contact " PACKAGE_BUGREPORT "\n", m_escalade_type, m_disknum);
     887    errno=ENOSYS;
     888    return -1;
     889  }
     890
     891  ata->opcode = TWE_OP_ATA_PASSTHROUGH;
     892
     893  // Same for (almost) all commands - but some reset below
     894  ata->request_id    = 0xFF;
     895  ata->unit          = m_disknum;
     896  ata->status        = 0;           
     897  ata->flags         = 0x1;
     898  ata->drive_head    = 0x0;
     899  ata->sector_num    = 0;
     900
     901  // All SMART commands use this CL/CH signature.  These are magic
     902  // values from the ATA specifications.
     903  ata->cylinder_lo   = 0x4F;
     904  ata->cylinder_hi   = 0xC2;
     905 
     906  // SMART ATA COMMAND REGISTER value
     907  ata->command       = ATA_SMART_CMD;
     908 
     909  // Is this a command that reads or returns 512 bytes?
     910  // passthru->param values are:
     911  // 0x0 - non data command without TFR write check,
     912  // 0x8 - non data command with TFR write check,
     913  // 0xD - data command that returns data to host from device
     914  // 0xF - data command that writes data from host to device
     915  // passthru->size values are 0x5 for non-data and 0x07 for data
     916  if (command == READ_VALUES     ||
     917      command == READ_THRESHOLDS ||
     918      command == READ_LOG        ||
     919      command == IDENTIFY        ||
     920      command == WRITE_LOG ) {
     921    readdata=1;
     922    if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
     923      cmd_twe->tu_data = data;
     924      cmd_twe->tu_size = 512;
     925    }
     926    ata->sgl_offset = 0x5;
     927    ata->size         = 0x5;
     928    ata->param        = 0xD;
     929    ata->sector_count = 0x1;
     930    // For 64-bit to work correctly, up the size of the command packet
     931    // in dwords by 1 to account for the 64-bit single sgl 'address'
     932    // field. Note that this doesn't agree with the typedefs but it's
     933    // right (agree with kernel driver behavior/typedefs).
     934    //if (sizeof(long)==8)
     935    //  ata->size++;
     936  }
     937  else {
     938    // Non data command -- but doesn't use large sector
     939    // count register values. 
     940    ata->sgl_offset = 0x0;
     941    ata->size         = 0x5;
     942    ata->param        = 0x8;
     943    ata->sector_count = 0x0;
     944  }
     945 
     946  // Now set ATA registers depending upon command
     947  switch (command){
     948  case CHECK_POWER_MODE:
     949    ata->command     = ATA_CHECK_POWER_MODE;
     950    ata->features    = 0;
     951    ata->cylinder_lo = 0;
     952    ata->cylinder_hi = 0;
     953    break;
     954  case READ_VALUES:
     955    ata->features = ATA_SMART_READ_VALUES;
     956    break;
     957  case READ_THRESHOLDS:
     958    ata->features = ATA_SMART_READ_THRESHOLDS;
     959    break;
     960  case READ_LOG:
     961    ata->features = ATA_SMART_READ_LOG_SECTOR;
     962    // log number to return
     963    ata->sector_num  = select;
     964    break;
     965  case WRITE_LOG:
     966    readdata=0;
     967    ata->features     = ATA_SMART_WRITE_LOG_SECTOR;
     968    ata->sector_count = 1;
     969    ata->sector_num   = select;
     970    ata->param        = 0xF;  // PIO data write
     971    break;
     972  case IDENTIFY:
     973    // ATA IDENTIFY DEVICE
     974    ata->command     = ATA_IDENTIFY_DEVICE;
     975    ata->features    = 0;
     976    ata->cylinder_lo = 0;
     977    ata->cylinder_hi = 0;
     978    break;
     979  case PIDENTIFY:
     980    // 3WARE controller can NOT have packet device internally
     981    pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum);
     982    errno=ENODEV;
     983    return -1;
     984  case ENABLE:
     985    ata->features = ATA_SMART_ENABLE;
     986    break;
     987  case DISABLE:
     988    ata->features = ATA_SMART_DISABLE;
     989    break;
     990  case AUTO_OFFLINE:
     991    ata->features     = ATA_SMART_AUTO_OFFLINE;
     992    // Enable or disable?
     993    ata->sector_count = select;
     994    break;
     995  case AUTOSAVE:
     996    ata->features     = ATA_SMART_AUTOSAVE;
     997    // Enable or disable?
     998    ata->sector_count = select;
     999    break;
     1000  case IMMEDIATE_OFFLINE:
     1001    ata->features    = ATA_SMART_IMMEDIATE_OFFLINE;
     1002    // What test type to run?
     1003    ata->sector_num  = select;
     1004    break;
     1005  case STATUS_CHECK:
     1006    ata->features = ATA_SMART_STATUS;
     1007    break;
     1008  case STATUS:
     1009    // This is JUST to see if SMART is enabled, by giving SMART status
     1010    // command. But it doesn't say if status was good, or failing.
     1011    // See below for the difference.
     1012    ata->features = ATA_SMART_STATUS;
     1013    break;
     1014  default:
     1015    pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
     1016         "Please contact " PACKAGE_BUGREPORT "\n", command, m_disknum);
     1017    errno=ENOSYS;
     1018    return -1;
     1019  }
     1020
     1021  // Now send the command down through an ioctl()
     1022  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
     1023#ifdef IOCATAREQUEST
     1024    ioctlreturn=ioctl(con->device,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
     1025#else
     1026    ioctlreturn=ioctl(con->atacommand,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
     1027#endif
     1028  } else {
     1029#ifdef IOCATAREQUEST
     1030    ioctlreturn=ioctl(con->device,TWEIO_COMMAND,cmd_twe);
     1031#else
     1032    ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd_twe);
     1033#endif
     1034  }
     1035
     1036  // Deal with the different error cases
     1037  if (ioctlreturn) {
     1038    if (!errno)
     1039      errno=EIO;
     1040    return -1;
     1041  }
     1042 
     1043  // See if the ATA command failed.  Now that we have returned from
     1044  // the ioctl() call, if passthru is valid, then:
     1045  // - ata->status contains the 3ware controller STATUS
     1046  // - ata->command contains the ATA STATUS register
     1047  // - ata->features contains the ATA ERROR register
     1048  //
     1049  // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
     1050  // If bit 0 (error bit) is set, then ATA ERROR register is valid.
     1051  // While we *might* decode the ATA ERROR register, at the moment it
     1052  // doesn't make much sense: we don't care in detail why the error
     1053  // happened.
     1054 
     1055  if (ata->status || (ata->command & 0x21)) {
     1056    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);
     1057    errno=EIO;
     1058    return -1;
     1059  }
     1060 
     1061  // If this is a read data command, copy data to output buffer
     1062  if (readdata) {
     1063    if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR)
     1064      memcpy(data, cmd_twa->pdata, 512);
     1065  }
     1066
     1067  // For STATUS_CHECK, we need to check register values
     1068  if (command==STATUS_CHECK) {
    2531069   
    254     "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
     1070    // To find out if the SMART RETURN STATUS is good or failing, we
     1071    // need to examine the values of the Cylinder Low and Cylinder
     1072    // High Registers.
    2551073   
    256     "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
     1074    unsigned short cyl_lo=ata->cylinder_lo;
     1075    unsigned short cyl_hi=ata->cylinder_hi;
    2571076   
    258     "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
    259   };
    260 
    261   if (msgNo >= 0 && msgNo <= MAX_MSG) {
    262     if (!printed[msgNo]) {
    263       printed[msgNo] = 1;
    264       pout("%s", message[msgNo]);
    265       if (extra)
    266         pout("%s",extra);
    267     }
     1077    // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
     1078    if (cyl_lo==0x4F && cyl_hi==0xC2)
     1079      return 0;
     1080   
     1081    // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
     1082    if (cyl_lo==0xF4 && cyl_hi==0x2C)
     1083      return 1;
     1084   
     1085      errno=EIO;
     1086      return -1;
    2681087  }
    269   return;
     1088 
     1089  // copy sector count register (one byte!) to return data
     1090  if (command==CHECK_POWER_MODE)
     1091    *data=*(char *)&(ata->sector_count);
     1092 
     1093  // look for nonexistent devices/ports
     1094  if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) {
     1095    errno=ENODEV;
     1096    return -1;
     1097  }
     1098 
     1099  return 0;
    2701100}
    2711101
    272 // Interface to ATA devices.  See os_linux.c
    2731102
    274 int marvell_command_interface(__unused int fd, __unused smart_command_set command, __unused int select, __unused char *data) {
    275   return -1;
     1103/////////////////////////////////////////////////////////////////////////////
     1104/// Implement Highpoint RAID support with old functions
     1105
     1106class freebsd_highpoint_device
     1107: public /*implements*/ ata_device_with_command_set,
     1108  public /*extends*/ freebsd_smart_device
     1109{
     1110public:
     1111  freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
     1112    unsigned char controller, unsigned char channel, unsigned char port);
     1113
     1114protected:
     1115  virtual int ata_command_interface(smart_command_set command, int select, char * data);
     1116
     1117private:
     1118  unsigned char m_hpt_data[3]; ///< controller/channel/port
     1119};
     1120
     1121
     1122freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
     1123  unsigned char controller, unsigned char channel, unsigned char port)
     1124: smart_device(intf, dev_name, "hpt", "hpt"),
     1125  freebsd_smart_device("ATA")
     1126{
     1127  m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port;
     1128  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]);
    2761129}
    2771130
    278 int highpoint_command_interface(int fd, smart_command_set command, int select, char *data) {
     1131int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
     1132{
     1133   int fd=get_fd();
    2791134  int ids[2];
    2801135  struct freebsd_dev_channel* fbcon;
    2811136  HPT_IOCTL_PARAM param;
     
    2881143      return -1;
    2891144
    2901145  // get internal deviceid
    291   ids[0] = con->hpt_data[0] - 1;
    292   ids[1] = con->hpt_data[1] - 1;
     1146  ids[0] = m_hpt_data[0] - 1;
     1147  ids[1] = m_hpt_data[1] - 1;
    2931148
    2941149  memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
    2951150
     
    3001155  param.out = (unsigned char *)&info;
    3011156  param.out_size = sizeof(HPT_CHANNEL_INFO_V2);
    3021157
    303   if (con->hpt_data[2]==1) {
     1158  if (m_hpt_data[2]==1) {
    3041159    param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO;
    3051160    param.out_size = sizeof(HPT_CHANNEL_INFO);
    3061161  }
    3071162  if (ioctl(fbcon->device, HPT_DO_IOCONTROL, &param)!=0 ||
    308       info.devices[con->hpt_data[2]-1]==0) {
     1163      info.devices[m_hpt_data[2]-1]==0) {
    3091164    return -1;
    3101165  }
    3111166
     
    3161171  pide_pt_hdr->lbamid = 0x4f;
    3171172  pide_pt_hdr->lbahigh = 0xc2;
    3181173  pide_pt_hdr->command = ATA_SMART_CMD;
    319   pide_pt_hdr->id = info.devices[con->hpt_data[2] - 1];
     1174  pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1];
    3201175
    3211176  switch (command){
    3221177  case READ_VALUES:
     
    4291284  return 0;
    4301285}
    4311286
    432 int areca_command_interface(__unused int fd, __unused int disknum, __unused smart_command_set command, __unused int select, __unused char *data) {
    433   return -1;
    434 }
    4351287
    436 int ata_command_interface(int fd, smart_command_set command, int select, char *data) {
    437 #if !defined(ATAREQUEST) && !defined(IOCATAREQUEST)
    438   // sorry, but without ATAng, we can't do anything here
    439   printwarning(BAD_KERNEL,NULL);
    440   errno = ENOSYS;
    441   return -1;
    442 #else
    443   struct freebsd_dev_channel* con;
    444   int retval, copydata=0;
    445 #ifdef IOCATAREQUEST
    446   struct ata_ioc_request request;
    447 #else
    448   struct ata_cmd iocmd;
    449 #endif
    450   unsigned char buff[512];
     1288/////////////////////////////////////////////////////////////////////////////
     1289/// Implement standard SCSI support with old functions
    4511290
    452   // check that "file descriptor" is valid
    453   if (isnotopen(&fd,&con))
    454       return -1;
     1291class freebsd_scsi_device
     1292: public /*implements*/ scsi_device,
     1293  public /*extends*/ freebsd_smart_device
     1294{
     1295public:
     1296  freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
    4551297
    456   bzero(buff,512);
     1298  virtual smart_device * autodetect_open();
    4571299
    458 #ifdef IOCATAREQUEST
    459   bzero(&request,sizeof(struct ata_ioc_request));
    460 #else
    461   bzero(&iocmd,sizeof(struct ata_cmd));
    462 #endif
    463   bzero(buff,512);
     1300  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
     1301};
    4641302
    465 #ifndef IOCATAREQUEST
    466   iocmd.cmd=ATAREQUEST;
    467   iocmd.channel=con->channel;
    468   iocmd.device=con->device;
    469 #define request iocmd.u.request
    470 #endif
    471 
    472   request.u.ata.command=ATA_SMART_CMD;
    473   request.timeout=600;
    474   switch (command){
    475   case READ_VALUES:
    476     request.u.ata.feature=ATA_SMART_READ_VALUES;
    477     request.u.ata.lba=0xc24f<<8;
    478     request.flags=ATA_CMD_READ;
    479     request.data=(char *)buff;
    480     request.count=512;
    481     copydata=1;
    482     break;
    483   case READ_THRESHOLDS:
    484     request.u.ata.feature=ATA_SMART_READ_THRESHOLDS;
    485     request.u.ata.count=1;
    486     request.u.ata.lba=1|(0xc24f<<8);
    487     request.flags=ATA_CMD_READ;
    488     request.data=(char *)buff;
    489     request.count=512;
    490     copydata=1;
    491     break;
    492   case READ_LOG:
    493     request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR;
    494     request.u.ata.lba=select|(0xc24f<<8);
    495     request.u.ata.count=1;
    496     request.flags=ATA_CMD_READ;
    497     request.data=(char *)buff;
    498     request.count=512;
    499     copydata=1;
    500     break;
    501   case IDENTIFY:
    502     request.u.ata.command=ATA_IDENTIFY_DEVICE;
    503     request.flags=ATA_CMD_READ;
    504     request.data=(char *)buff;
    505     request.count=512;
    506     copydata=1;
    507     break;
    508   case PIDENTIFY:
    509     request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE;
    510     request.flags=ATA_CMD_READ;
    511     request.data=(char *)buff;
    512     request.count=512;
    513     copydata=1;
    514     break;
    515   case ENABLE:
    516     request.u.ata.feature=ATA_SMART_ENABLE;
    517     request.u.ata.lba=0xc24f<<8;
    518     request.flags=ATA_CMD_CONTROL;
    519     break;
    520   case DISABLE:
    521     request.u.ata.feature=ATA_SMART_DISABLE;
    522     request.u.ata.lba=0xc24f<<8;
    523     request.flags=ATA_CMD_CONTROL;
    524     break;
    525   case AUTO_OFFLINE:
    526     // NOTE: According to ATAPI 4 and UP, this command is obsolete
    527     request.u.ata.feature=ATA_SMART_AUTO_OFFLINE;
    528     request.u.ata.lba=0xc24f<<8;                                                                                                                                         
    529     request.u.ata.count=select;                                                                                                                                         
    530     request.flags=ATA_CMD_CONTROL;
    531     break;
    532   case AUTOSAVE:
    533     request.u.ata.feature=ATA_SMART_AUTOSAVE;
    534     request.u.ata.lba=0xc24f<<8;
    535     request.u.ata.count=select;
    536     request.flags=ATA_CMD_CONTROL;
    537     break;
    538   case IMMEDIATE_OFFLINE:
    539     request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE;
    540     request.u.ata.lba = select|(0xc24f<<8); // put test in sector
    541     request.flags=ATA_CMD_CONTROL;
    542     break;
    543   case STATUS_CHECK: // same command, no HDIO in FreeBSD
    544   case STATUS:
    545     // this command only says if SMART is working.  It could be
    546     // replaced with STATUS_CHECK below.
    547     request.u.ata.feature=ATA_SMART_STATUS;
    548     request.u.ata.lba=0xc24f<<8;
    549     request.flags=ATA_CMD_CONTROL;
    550     break;
    551   case CHECK_POWER_MODE:
    552     request.u.ata.command=ATA_CHECK_POWER_MODE;
    553     request.u.ata.feature=0;
    554     request.flags=ATA_CMD_CONTROL;
    555     break;
    556   case WRITE_LOG:
    557     memcpy(buff, data, 512);
    558     request.u.ata.feature=ATA_SMART_WRITE_LOG_SECTOR;
    559     request.u.ata.lba=select|(0xc24f<<8);
    560     request.u.ata.count=1;
    561     request.flags=ATA_CMD_WRITE;
    562     request.data=(char *)buff;
    563     request.count=512;
    564     break;
    565   default:
    566     pout("Unrecognized command %d in ata_command_interface()\n"
    567          "Please contact " PACKAGE_BUGREPORT "\n", command);
    568     errno=ENOSYS;
    569     return -1;
    570   }
    571  
    572   if (command==STATUS_CHECK){
    573     unsigned const char normal_lo=0x4f, normal_hi=0xc2;
    574     unsigned const char failed_lo=0xf4, failed_hi=0x2c;
    575     unsigned char low,high;
    576    
    577 #ifdef IOCATAREQUEST
    578     if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)
    579 #else
    580     if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
    581 #endif
    582       return -1;
    583 
    584 #if __FreeBSD_version < 502000
    585     printwarning(NO_RETURN,NULL);
    586 #endif
    587 
    588     high = (request.u.ata.lba >> 16) & 0xff;
    589     low = (request.u.ata.lba >> 8) & 0xff;
    590    
    591     // Cyl low and Cyl high unchanged means "Good SMART status"
    592     if (low==normal_lo && high==normal_hi)
    593       return 0;
    594    
    595     // These values mean "Bad SMART status"
    596     if (low==failed_lo && high==failed_hi)
    597       return 1;
    598    
    599     // We haven't gotten output that makes sense; print out some debugging info
    600     char buf[512];
    601     sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
    602             (int)request.u.ata.command,
    603             (int)request.u.ata.feature,
    604             (int)request.u.ata.count,
    605             (int)((request.u.ata.lba) & 0xff),
    606             (int)((request.u.ata.lba>>8) & 0xff),
    607             (int)((request.u.ata.lba>>16) & 0xff),
    608             (int)request.error);
    609     printwarning(BAD_SMART,buf);
    610     return 0;   
    611   }
    612 
    613 #ifdef IOCATAREQUEST
    614   if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error)
    615 #else
    616   if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
    617 #endif
    618   {
    619     return -1;
    620   }
    621   //
    622   if (command == CHECK_POWER_MODE) {
    623     data[0] = request.u.ata.count & 0xff;
    624     return 0;
    625   }
    626   if (copydata)
    627     memcpy(data, buff, 512);
    628  
    629   return 0;
    630 #endif
     1303freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
     1304  const char * dev_name, const char * req_type)
     1305: smart_device(intf, dev_name, "scsi", req_type),
     1306  freebsd_smart_device("SCSI")
     1307{
    6311308}
    6321309
    633 
    6341310// Interface to SCSI devices.  See os_linux.c
    6351311int do_normal_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
    6361312{
     
    7331409  return 0;
    7341410}
    7351411
     1412
    7361413/* Check and call the right interface. Maybe when the do_generic_scsi_cmd_io interface is better
    7371414   we can take off this crude way of calling the right interface */
    7381415int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report)
    7391416{
    7401417struct freebsd_dev_channel *fdchan;
    741      switch(con->controller_type)
     1418     switch(m_controller_type)
    7421419     {
    7431420         case CONTROLLER_CCISS:
    7441421#ifdef HAVE_DEV_CISS_CISSIO_H
    7451422             // check that "file descriptor" is valid
    7461423             if (isnotopen(&dev_fd,&fdchan))
    7471424                 return -ENOTTY;
    748              return cciss_io_interface(fdchan->device, con->controller_port-1, iop, report);
     1425             return cciss_io_interface(fdchan->device, m_controller_port-1, iop, report);
    7491426#else
    7501427             {
    7511428                 static int warned = 0;
     
    7661443     }
    7671444}
    7681445
    769 // Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
     1446bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
     1447{
     1448  unsigned char oldtype = m_controller_type, oldport = m_controller_port;
     1449  m_controller_type = CONTROLLER_SCSI; m_controller_port = 0;
     1450  int status = do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
     1451  m_controller_type = oldtype; m_controller_port = oldport;
     1452  if (status < 0) {
     1453      set_err(-status);
     1454      return false;
     1455  }
     1456  return true;
     1457}
    7701458
    771 #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
    772 #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
    773 #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
    7741459
    775 int escalade_command_interface(int fd, int disknum, int escalade_type, smart_command_set command, int select, char *data) {
    776   // to hold true file descriptor
    777   struct freebsd_dev_channel* con;
     1460/////////////////////////////////////////////////////////////////////////////
     1461/// Implement CCISS RAID support with old functions
    7781462
    779   // return value and buffer for ioctl()
    780   int  ioctlreturn, readdata=0;
    781   struct twe_usercommand* cmd_twe = NULL;
    782   TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
    783   TWE_Command_ATA* ata = NULL;
     1463class freebsd_cciss_device
     1464: public /*implements*/ scsi_device,
     1465  public /*extends*/ freebsd_smart_device
     1466{
     1467public:
     1468  freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
    7841469
    785   // Used by both the SCSI and char interfaces
    786   char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
     1470  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
    7871471
    788   if (disknum < 0) {
    789     printwarning(NO_DISK_3WARE,NULL);
    790     return -1;
    791   }
     1472private:
     1473  unsigned char m_disknum; ///< Disk number.
     1474};
    7921475
    793   // check that "file descriptor" is valid
    794   if (isnotopen(&fd,&con))
    795       return -1;
    7961476
    797   memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
     1477freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
     1478  const char * dev_name, unsigned char disknum)
     1479: smart_device(intf, dev_name, "cciss", "cciss"),
     1480  freebsd_smart_device("SCSI"),
     1481  m_disknum(disknum)
     1482{
     1483  set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
     1484}
    7981485
    799   if (escalade_type==CONTROLLER_3WARE_9000_CHAR) {
    800     cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
    801     cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
    802     cmd_twa->driver_pkt.buffer_length = 512;
    803     ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
    804   } else if (escalade_type==CONTROLLER_3WARE_678K_CHAR) {
    805     cmd_twe = (struct twe_usercommand*)ioctl_buffer;
    806     ata = &cmd_twe->tu_command.ata;
    807   } else {
    808     pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
    809          "Please contact " PACKAGE_BUGREPORT "\n", escalade_type, disknum);
    810     errno=ENOSYS;
    811     return -1;
     1486bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
     1487{
     1488  // See os_linux.cpp
     1489  unsigned char oldtype = m_controller_type, oldport = m_controller_port;
     1490  m_controller_type = CONTROLLER_CCISS; m_controller_port = m_disknum+1;
     1491  int status = do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
     1492  m_controller_type = oldtype; m_controller_port = oldport;
     1493  if (status < 0) {
     1494      set_err(-status);
     1495      return false;
    8121496  }
     1497  return true;
     1498}
    8131499
    814   ata->opcode = TWE_OP_ATA_PASSTHROUGH;
    8151500
    816   // Same for (almost) all commands - but some reset below
    817   ata->request_id    = 0xFF;
    818   ata->unit          = disknum;
    819   ata->status        = 0;           
    820   ata->flags         = 0x1;
    821   ata->drive_head    = 0x0;
    822   ata->sector_num    = 0;
     1501/////////////////////////////////////////////////////////////////////////////
     1502/// SCSI open with autodetection support
    8231503
    824   // All SMART commands use this CL/CH signature.  These are magic
    825   // values from the ATA specifications.
    826   ata->cylinder_lo   = 0x4F;
    827   ata->cylinder_hi   = 0xC2;
    828  
    829   // SMART ATA COMMAND REGISTER value
    830   ata->command       = ATA_SMART_CMD;
    831  
    832   // Is this a command that reads or returns 512 bytes?
    833   // passthru->param values are:
    834   // 0x0 - non data command without TFR write check,
    835   // 0x8 - non data command with TFR write check,
    836   // 0xD - data command that returns data to host from device
    837   // 0xF - data command that writes data from host to device
    838   // passthru->size values are 0x5 for non-data and 0x07 for data
    839   if (command == READ_VALUES     ||
    840       command == READ_THRESHOLDS ||
    841       command == READ_LOG        ||
    842       command == IDENTIFY        ||
    843       command == WRITE_LOG ) {
    844     readdata=1;
    845     if (escalade_type==CONTROLLER_3WARE_678K_CHAR) {
    846       cmd_twe->tu_data = data;
    847       cmd_twe->tu_size = 512;
     1504smart_device * freebsd_scsi_device::autodetect_open()
     1505{
     1506  // Open device
     1507  if (!open())
     1508    return this;
     1509
     1510  // No Autodetection if device type was specified by user
     1511  if (*get_req_type())
     1512    return this;
     1513
     1514  // The code below is based on smartd.cpp:SCSIFilterKnown()
     1515
     1516  // Get INQUIRY
     1517  unsigned char req_buff[64] = {0, };
     1518  int req_len = 36;
     1519  if (scsiStdInquiry(this, req_buff, req_len)) {
     1520    // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
     1521    // watch this spot ... other devices could lock up here
     1522    req_len = 64;
     1523    if (scsiStdInquiry(this, req_buff, req_len)) {
     1524      // device doesn't like INQUIRY commands
     1525      close();
     1526      set_err(EIO, "INQUIRY failed");
     1527      return this;
    8481528    }
    849     ata->sgl_offset = 0x5;
    850     ata->size         = 0x5;
    851     ata->param        = 0xD;
    852     ata->sector_count = 0x1;
    853     // For 64-bit to work correctly, up the size of the command packet
    854     // in dwords by 1 to account for the 64-bit single sgl 'address'
    855     // field. Note that this doesn't agree with the typedefs but it's
    856     // right (agree with kernel driver behavior/typedefs).
    857     //if (sizeof(long)==8)
    858     //  ata->size++;
    8591529  }
    860   else {
    861     // Non data command -- but doesn't use large sector
    862     // count register values. 
    863     ata->sgl_offset = 0x0;
    864     ata->size         = 0x5;
    865     ata->param        = 0x8;
    866     ata->sector_count = 0x0;
    867   }
    868  
    869   // Now set ATA registers depending upon command
    870   switch (command){
    871   case CHECK_POWER_MODE:
    872     ata->command     = ATA_CHECK_POWER_MODE;
    873     ata->features    = 0;
    874     ata->cylinder_lo = 0;
    875     ata->cylinder_hi = 0;
    876     break;
    877   case READ_VALUES:
    878     ata->features = ATA_SMART_READ_VALUES;
    879     break;
    880   case READ_THRESHOLDS:
    881     ata->features = ATA_SMART_READ_THRESHOLDS;
    882     break;
    883   case READ_LOG:
    884     ata->features = ATA_SMART_READ_LOG_SECTOR;
    885     // log number to return
    886     ata->sector_num  = select;
    887     break;
    888   case WRITE_LOG:
    889     readdata=0;
    890     ata->features     = ATA_SMART_WRITE_LOG_SECTOR;
    891     ata->sector_count = 1;
    892     ata->sector_num   = select;
    893     ata->param        = 0xF;  // PIO data write
    894     break;
    895   case IDENTIFY:
    896     // ATA IDENTIFY DEVICE
    897     ata->command     = ATA_IDENTIFY_DEVICE;
    898     ata->features    = 0;
    899     ata->cylinder_lo = 0;
    900     ata->cylinder_hi = 0;
    901     break;
    902   case PIDENTIFY:
    903     // 3WARE controller can NOT have packet device internally
    904     pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", disknum);
    905     errno=ENODEV;
    906     return -1;
    907   case ENABLE:
    908     ata->features = ATA_SMART_ENABLE;
    909     break;
    910   case DISABLE:
    911     ata->features = ATA_SMART_DISABLE;
    912     break;
    913   case AUTO_OFFLINE:
    914     ata->features     = ATA_SMART_AUTO_OFFLINE;
    915     // Enable or disable?
    916     ata->sector_count = select;
    917     break;
    918   case AUTOSAVE:
    919     ata->features     = ATA_SMART_AUTOSAVE;
    920     // Enable or disable?
    921     ata->sector_count = select;
    922     break;
    923   case IMMEDIATE_OFFLINE:
    924     ata->features    = ATA_SMART_IMMEDIATE_OFFLINE;
    925     // What test type to run?
    926     ata->sector_num  = select;
    927     break;
    928   case STATUS_CHECK:
    929     ata->features = ATA_SMART_STATUS;
    930     break;
    931   case STATUS:
    932     // This is JUST to see if SMART is enabled, by giving SMART status
    933     // command. But it doesn't say if status was good, or failing.
    934     // See below for the difference.
    935     ata->features = ATA_SMART_STATUS;
    936     break;
    937   default:
    938     pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
    939          "Please contact " PACKAGE_BUGREPORT "\n", command, disknum);
    940     errno=ENOSYS;
    941     return -1;
    942   }
    9431530
    944   // Now send the command down through an ioctl()
    945   if (escalade_type==CONTROLLER_3WARE_9000_CHAR) {
    946 #ifdef IOCATAREQUEST
    947     ioctlreturn=ioctl(con->device,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
     1531  int avail_len = req_buff[4] + 5;
     1532  int len = (avail_len < req_len ? avail_len : req_len);
     1533  if (len < 36)
     1534      return this;
     1535
     1536  // Use INQUIRY to detect type
     1537  smart_device * newdev = 0;
     1538  try {
     1539    // 3ware ?
     1540    if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
     1541      close();
     1542#if defined(_WIN32) || defined(__CYGWIN__)
     1543      set_err(EINVAL, "AMCC/3ware controller, please try changing device to %s,N", get_dev_name());
    9481544#else
    949     ioctlreturn=ioctl(con->atacommand,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
     1545      set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
     1546                      "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
    9501547#endif
    951   } else {
    952 #ifdef IOCATAREQUEST
    953     ioctlreturn=ioctl(con->device,TWEIO_COMMAND,cmd_twe);
    954 #else
    955     ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd_twe);
    956 #endif
    957   }
     1548      return this;
     1549    }
    9581550
    959   // Deal with the different error cases
    960   if (ioctlreturn) {
    961     if (!errno)
    962       errno=EIO;
    963     return -1;
     1551    // SAT or USB ?
     1552    newdev = smi()->autodetect_sat_device(this, req_buff, len);
     1553    if (newdev)
     1554      // NOTE: 'this' is now owned by '*newdev'
     1555      return newdev;
    9641556  }
    965  
    966   // See if the ATA command failed.  Now that we have returned from
    967   // the ioctl() call, if passthru is valid, then:
    968   // - ata->status contains the 3ware controller STATUS
    969   // - ata->command contains the ATA STATUS register
    970   // - ata->features contains the ATA ERROR register
    971   //
    972   // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
    973   // If bit 0 (error bit) is set, then ATA ERROR register is valid.
    974   // While we *might* decode the ATA ERROR register, at the moment it
    975   // doesn't make much sense: we don't care in detail why the error
    976   // happened.
    977  
    978   if (ata->status || (ata->command & 0x21)) {
    979     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);
    980     errno=EIO;
    981     return -1;
     1557  catch (...) {
     1558    // Cleanup if exception occurs after newdev was allocated
     1559    delete newdev;
     1560    throw;
    9821561  }
    983  
    984   // If this is a read data command, copy data to output buffer
    985   if (readdata) {
    986     if (escalade_type==CONTROLLER_3WARE_9000_CHAR)
    987       memcpy(data, cmd_twa->pdata, 512);
    988   }
    9891562
    990   // For STATUS_CHECK, we need to check register values
    991   if (command==STATUS_CHECK) {
    992    
    993     // To find out if the SMART RETURN STATUS is good or failing, we
    994     // need to examine the values of the Cylinder Low and Cylinder
    995     // High Registers.
    996    
    997     unsigned short cyl_lo=ata->cylinder_lo;
    998     unsigned short cyl_hi=ata->cylinder_hi;
    999    
    1000     // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
    1001     if (cyl_lo==0x4F && cyl_hi==0xC2)
    1002       return 0;
    1003    
    1004     // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
    1005     if (cyl_lo==0xF4 && cyl_hi==0x2C)
    1006       return 1;
    1007    
    1008       errno=EIO;
    1009       return -1;
    1010   }
    1011  
    1012   // copy sector count register (one byte!) to return data
    1013   if (command==CHECK_POWER_MODE)
    1014     *data=*(char *)&(ata->sector_count);
    1015  
    1016   // look for nonexistent devices/ports
    1017   if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) {
    1018     errno=ENODEV;
    1019     return -1;
    1020   }
    1021  
    1022   return 0;
     1563  // Nothing special found
     1564  return this;
    10231565}
    10241566
    1025 static int get_tw_channel_unit (const char* name, int* unit, int* dev) {
    1026   const char *p;
    10271567
    1028   /* device node sanity check */
    1029   for (p = name + 3; *p; p++)
    1030     if (*p < '0' || *p > '9')
    1031       return -1;
    1032   if (strlen(name) > 4 && *(name + 3) == '0')
    1033     return -1;
     1568/////////////////////////////////////////////////////////////////////////////
     1569/// Implement platform interface with old functions.
    10341570
    1035   if (dev != NULL)
    1036     *dev=atoi(name + 3);
     1571class freebsd_smart_interface
     1572: public /*implements*/ smart_interface
     1573{
     1574public:
     1575  virtual const char * get_os_version_str();
    10371576
    1038   /* no need for unit number */
    1039   if (unit != NULL)
    1040     *unit=0;
    1041   return 0;
    1042 }
     1577  virtual const char * get_app_examples(const char * appname);
    10431578
    1044 static int hpt_hba(const char* name) {
    1045   int i=0;
    1046   const char *hpt_node[]={"hptmv", "hptmv6", "hptrr", "hptiop", "hptmviop", "hpt32xx", "rr2320",
    1047                           "rr232x", "rr2310", "rr2310_00", "rr2300", "rr2340", "rr1740", NULL};
    1048   while (hpt_node[i]) {
    1049     if (!strncmp(name, hpt_node[i], strlen(hpt_node[i])))
    1050       return 1;
    1051     i++;
    1052   }
    1053   return 0;
    1054 }
     1579  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
     1580    const char * pattern = 0);
    10551581
    1056 #ifndef ATA_DEVICE
    1057 #define ATA_DEVICE "/dev/ata"
    1058 #endif
     1582protected:
     1583  virtual ata_device * get_ata_device(const char * name, const char * type);
    10591584
    1060 #ifndef IOCATAREQUEST
    1061 static int get_ata_channel_unit ( const char* name, int* unit, int* dev) {
    1062 #ifndef ATAREQUEST
    1063   *dev=0;
    1064   *unit=0;
    1065 return 0;
    1066 #else
    1067   // there is no direct correlation between name 'ad0, ad1, ...' and
    1068   // channel/unit number.  So we need to iterate through the possible
    1069   // channels and check each unit to see if we match names
    1070   struct ata_cmd iocmd;
    1071   int fd,maxunit;
    1072  
    1073   bzero(&iocmd, sizeof(struct ata_cmd));
     1585  virtual scsi_device * get_scsi_device(const char * name, const char * type);
    10741586
    1075   if ((fd = open(ATA_DEVICE, O_RDWR)) < 0)
    1076     return -errno;
    1077  
    1078   iocmd.cmd = ATAGMAXCHANNEL;
    1079   if (ioctl(fd, IOCATA, &iocmd) < 0) {
    1080     return -errno;
    1081     close(fd);
    1082   }
    1083   maxunit = iocmd.u.maxchan;
    1084   for (*unit = 0; *unit < maxunit; (*unit)++) {
    1085     iocmd.channel = *unit;
    1086     iocmd.device = -1;
    1087     iocmd.cmd = ATAGPARM;
    1088     if (ioctl(fd, IOCATA, &iocmd) < 0) {
    1089       close(fd);
    1090       return -errno;
    1091     }
    1092     if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) {
    1093       *dev = 0;
    1094       break;
    1095     }
    1096     if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) {
    1097       *dev = 1;
    1098       break;
    1099     }
    1100   }
    1101   close(fd);
    1102   if (*unit == maxunit)
    1103     return -1;
    1104   else
    1105     return 0;
    1106 #endif
    1107 }
    1108 #endif
     1587  virtual smart_device * autodetect_smart_device(const char * name);
    11091588
    1110 // Guess device type (ata or scsi) based on device name (FreeBSD
    1111 // specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst,
    1112 // osst, nosst and sg.
    1113 static const char * fbsd_dev_prefix = _PATH_DEV;
    1114 static const char * fbsd_dev_ata_disk_prefix = "ad";
    1115 static const char * fbsd_dev_scsi_disk_plus = "da";
    1116 static const char * fbsd_dev_scsi_pass = "pass";
    1117 static const char * fbsd_dev_scsi_tape1 = "sa";
    1118 static const char * fbsd_dev_scsi_tape2 = "nsa";
    1119 static const char * fbsd_dev_scsi_tape3 = "esa";
    1120 static const char * fbsd_dev_twe_ctrl = "twe";
    1121 static const char * fbsd_dev_twa_ctrl = "twa";
    1122 static const char * fbsd_dev_cciss = "ciss";
     1589  virtual smart_device * get_custom_smart_device(const char * name, const char * type);
    11231590
    1124 static int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan) {
    1125   int len;
    1126   int dev_prefix_len = strlen(fbsd_dev_prefix);
    1127  
    1128   // if dev_name null, or string length zero
    1129   if (!dev_name || !(len = strlen(dev_name)))
    1130     return CONTROLLER_UNKNOWN;
    1131  
    1132   // Remove the leading /dev/... if it's there
    1133   if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) {
    1134     if (len <= dev_prefix_len)
    1135       // if nothing else in the string, unrecognized
    1136       return CONTROLLER_UNKNOWN;
    1137     // else advance pointer to following characters
    1138     dev_name += dev_prefix_len;
    1139   }
    1140   // form /dev/ad* or ad*
    1141   if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name,
    1142                strlen(fbsd_dev_ata_disk_prefix))) {
    1143 #ifndef IOCATAREQUEST
    1144     if (chan != NULL) {
    1145       if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
    1146         return CONTROLLER_UNKNOWN;
    1147       }
    1148     }
    1149 #endif
    1150     return CONTROLLER_ATA;
    1151   }
     1591  virtual const char * get_valid_custom_dev_types_str();
     1592};
    11521593
    1153   // form /dev/pass* or pass*
    1154   if (!strncmp(fbsd_dev_scsi_pass, dev_name,
    1155                strlen(fbsd_dev_scsi_pass)))
    1156     goto handlescsi;
    11571594
    1158   // form /dev/da* or da*
    1159   if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name,
    1160                strlen(fbsd_dev_scsi_disk_plus)))
    1161     goto handlescsi;
     1595//////////////////////////////////////////////////////////////////////
     1596char sysname[256];
     1597const char * freebsd_smart_interface::get_os_version_str()
     1598{
     1599 struct utsname osname;
     1600 uname(&osname);
     1601 snprintf(sysname, sizeof(sysname),"%s %s %s",osname.sysname, osname.release,
     1602         osname.machine);
     1603  return sysname;
     1604}
    11621605
    1163   // form /dev/sa* or sa*
    1164   if (!strncmp(fbsd_dev_scsi_tape1, dev_name,
    1165               strlen(fbsd_dev_scsi_tape1)))
    1166     goto handlescsi;
     1606const char * freebsd_smart_interface::get_app_examples(const char * appname)
     1607{
     1608  if (!strcmp(appname, "smartctl"))
     1609    return smartctl_examples;
     1610   return 0;
     1611}
    11671612
    1168   // form /dev/nsa* or nsa*
    1169   if (!strncmp(fbsd_dev_scsi_tape2, dev_name,
    1170               strlen(fbsd_dev_scsi_tape2)))
    1171     goto handlescsi;
     1613ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
     1614{
     1615  return new freebsd_ata_device(this, name, type);
     1616}
    11721617
    1173   // form /dev/esa* or esa*
    1174   if (!strncmp(fbsd_dev_scsi_tape3, dev_name,
    1175               strlen(fbsd_dev_scsi_tape3)))
    1176     goto handlescsi;
    1177  
    1178   if (!strncmp(fbsd_dev_twa_ctrl,dev_name,
    1179                strlen(fbsd_dev_twa_ctrl))) {
    1180     if (chan != NULL) {
    1181       if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
    1182         return CONTROLLER_UNKNOWN;
    1183       }
    1184     }
    1185     else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
    1186         return CONTROLLER_UNKNOWN;
    1187     }
    1188     return CONTROLLER_3WARE_9000_CHAR;
    1189   }
     1618scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
     1619{
     1620  return new freebsd_scsi_device(this, name, type);
     1621}
    11901622
    1191   if (!strncmp(fbsd_dev_twe_ctrl,dev_name,
    1192                strlen(fbsd_dev_twe_ctrl))) {
    1193     if (chan != NULL) {
    1194       if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
    1195         return CONTROLLER_UNKNOWN;
    1196       }
    1197     }
    1198     else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
    1199         return CONTROLLER_UNKNOWN;
    1200     }
    1201     return CONTROLLER_3WARE_678K_CHAR;
    1202   }
     1623static int
     1624cam_getumassno(char * devname) {
     1625        union ccb ccb;
     1626        int bufsize, fd;
     1627        unsigned int i;
     1628        int error = -1;
     1629        char devstring[256];
     1630       
     1631        if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
     1632                warn("couldn't open %s", XPT_DEVICE);
     1633                return(1);
     1634        }
     1635        bzero(&ccb, sizeof(union ccb));
    12031636
    1204   if (hpt_hba(dev_name)) {
    1205     return CONTROLLER_HPT;
    1206   }
     1637        ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
     1638        ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
     1639        ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
    12071640
    1208   // form /dev/ciss*
    1209   if (!strncmp(fbsd_dev_cciss, dev_name,
    1210                strlen(fbsd_dev_cciss)))
    1211     return CONTROLLER_CCISS;
     1641        ccb.ccb_h.func_code = XPT_DEV_MATCH;
     1642        bufsize = sizeof(struct dev_match_result) * 100;
     1643        ccb.cdm.match_buf_len = bufsize;
     1644        ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
     1645        if (ccb.cdm.matches == NULL) {
     1646                warnx("can't malloc memory for matches");
     1647                close(fd);
     1648                return(1);
     1649        }
     1650        ccb.cdm.num_matches = 0;
     1651        /*
     1652         * We fetch all nodes, since we display most of them in the default
     1653         * case, and all in the verbose case.
     1654         */
     1655        ccb.cdm.num_patterns = 0;
     1656        ccb.cdm.pattern_buf_len = 0;
     1657        /*
     1658         * We do the ioctl multiple times if necessary, in case there are
     1659         * more than 100 nodes in the EDT.
     1660         */
     1661         
     1662        do {
     1663                if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
     1664                        warn("error sending CAMIOCOMMAND ioctl");
     1665                        error = -1;
     1666                        break;
     1667                }
     1668                if ((ccb.ccb_h.status != CAM_REQ_CMP)
     1669                 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
     1670                    && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
     1671                        warnx("got CAM error %#x, CDM error %d\n",
     1672                              ccb.ccb_h.status, ccb.cdm.status);
     1673                        error = -1;
     1674                        break;
     1675                }
    12121676
    1213   // we failed to recognize any of the forms
    1214   return CONTROLLER_UNKNOWN;
     1677                struct bus_match_result *bus_result = 0;
     1678                for (i = 0; i < ccb.cdm.num_matches; i++) {
     1679                        switch (ccb.cdm.matches[i].type) {
     1680                        case DEV_MATCH_BUS: {
     1681                                // struct bus_match_result *bus_result;
     1682                                bus_result =
     1683                                        &ccb.cdm.matches[i].result.bus_result;
     1684                                break;
     1685                        }
     1686                        case DEV_MATCH_DEVICE: {
     1687                                /* we are not interested in device name */
     1688                                break;
     1689                        }
     1690                        case DEV_MATCH_PERIPH: {
     1691                                struct periph_match_result *periph_result;
    12151692
    1216  handlescsi:
    1217   if (chan != NULL) {
    1218     if (!(chan->devname = (char *)calloc(1,DEV_IDLEN+1)))
    1219       return CONTROLLER_UNKNOWN;
    1220    
    1221     if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1)
    1222       return CONTROLLER_UNKNOWN;
    1223   }
    1224   return CONTROLLER_SCSI;
    1225  
    1226 }
     1693                                periph_result =
     1694                                      &ccb.cdm.matches[i].result.periph_result;
    12271695
    1228 int guess_device_type (const char* dev_name) {
    1229   return parse_ata_chan_dev(dev_name,NULL);
     1696                                snprintf(devstring,sizeof(devstring),"%s%d",periph_result->periph_name,periph_result->unit_number);
     1697                                if(strcmp(devstring,devname)==0){ /* found our device */
     1698                                    if(strcmp(bus_result->dev_name,"umass-sim")) {
     1699                                        close(fd);
     1700                                        return -1; /* non usb device found, giving up */
     1701                                    }
     1702                                    /* return bus number */
     1703                                    return  bus_result->unit_number;
     1704                                }
     1705                                break;
     1706                        }
     1707                       
     1708                        default:
     1709                                fprintf(stdout, "WARN: unknown match type\n");
     1710                                break;
     1711                        }
     1712                }
     1713
     1714        } while ((ccb.ccb_h.status == CAM_REQ_CMP)
     1715                && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
     1716        close(fd);
     1717        free(ccb.cdm.matches);
     1718        return(error); /* no device found */
    12301719}
    12311720
    1232 // global variable holding byte count of allocated memory
    1233 extern long long bytes;
    12341721
    12351722// we are using CAM subsystem XPT enumerator to found all SCSI devices on system
    12361723// despite of it's names
     
    14771964  return n;
    14781965}
    14791966
    1480 int make_device_names (char*** devlist, const char* name) {
    1481   if (!strcmp(name,"SCSI"))
    1482     return get_dev_names_scsi(devlist);
    1483   else if (!strcmp(name,"ATA"))
    1484     return get_dev_names_ata(devlist);
    1485   else
     1967
     1968
     1969bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
     1970  const char * type, const char * pattern /*= 0*/)
     1971{
     1972  if (pattern) {
     1973    set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
     1974    return false;
     1975  }
     1976
     1977  // Make namelists
     1978  char * * atanames = 0; int numata = 0;
     1979  if (!type || !strcmp(type, "ata")) {
     1980    numata = get_dev_names_ata(&atanames);
     1981    if (numata < 0) {
     1982      set_err(ENOMEM);
     1983      return false;
     1984    }
     1985  }
     1986
     1987  char * * scsinames = 0; int numscsi = 0;
     1988  if (!type || !strcmp(type, "scsi")) {
     1989    numscsi = get_dev_names_scsi(&scsinames);
     1990    if (numscsi < 0) {
     1991      set_err(ENOMEM);
     1992      return false;
     1993    }
     1994  }
     1995
     1996  // Add to devlist
     1997  int i;
     1998  if (type==NULL)
     1999    type="";
     2000  for (i = 0; i < numata; i++) {
     2001    ata_device * atadev = get_ata_device(atanames[i], type);
     2002    if (atadev)
     2003      devlist.add(atadev);
     2004  }
     2005
     2006  for (i = 0; i < numscsi; i++) {
     2007    scsi_device * scsidev = get_scsi_device(scsinames[i], type);
     2008    if (scsidev)
     2009      devlist.add(scsidev);
     2010  }
     2011  return true;
     2012}
     2013
     2014
     2015static char done[USB_MAX_DEVICES];
     2016// static unsigned short vendor_id = 0, product_id = 0, version = 0;
     2017
     2018static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
     2019                       unsigned short & product_id, unsigned short & version)
     2020{
     2021        struct usb_device_info di;
     2022        int e, p, i;
     2023        char devname[256];
     2024
     2025        snprintf(devname, sizeof(devname),"umass%d",busno);
     2026       
     2027        di.udi_addr = a;
     2028        e = ioctl(f, USB_DEVICEINFO, &di);
     2029        if (e) {
     2030                if (errno != ENXIO)
     2031                        printf("addr %d: I/O error\n", a);
     2032                return 0;
     2033        }
     2034        done[a] = 1;
     2035       
     2036                // list devices
     2037                for (i = 0; i < USB_MAX_DEVNAMES; i++) {
     2038                        if (di.udi_devnames[i][0]) {
     2039                                if(strcmp(di.udi_devnames[i],devname)==0) {
     2040                                 // device found!
     2041                                    vendor_id = di.udi_vendorNo;
     2042                                    product_id = di.udi_productNo;
     2043                                    version = di.udi_releaseNo;
     2044                                    return 1;
     2045                                    // FIXME
     2046                                }
     2047                        }
     2048                }
     2049        if (!rec)
     2050                return 0;
     2051        for (p = 0; p < di.udi_nports; p++) {
     2052                int s = di.udi_ports[p];
     2053                if (s >= USB_MAX_DEVICES) {
     2054                        continue;
     2055                }
     2056                if (s == 0)
     2057                        printf("addr 0 should never happen!\n");
     2058                else {
     2059                        if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
     2060                }
     2061        }
     2062        return 0;
     2063}
     2064
     2065
     2066
     2067
     2068static int usbdevlist(int busno,unsigned short & vendor_id,
     2069                       unsigned short & product_id, unsigned short & version)
     2070{
     2071    int  i, f, a, rc;
     2072    char buf[50];
     2073    int ncont;
     2074
     2075    for (ncont = 0, i = 0; i < 10; i++) {
     2076        snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
     2077        f = open(buf, O_RDONLY);
     2078        if (f >= 0) {
     2079            memset(done, 0, sizeof done);
     2080            for (a = 1; a < USB_MAX_DEVICES; a++) {
     2081                if (!done[a]) {
     2082                    rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
     2083                    if(rc) return 1;
     2084                }
     2085               
     2086            }
     2087        close(f);
     2088        } else {
     2089            if (errno == ENOENT || errno == ENXIO)
     2090                continue;
     2091            warn("%s", buf);
     2092        }
     2093        ncont++;
     2094    }
    14862095    return 0;
    14872096}
     2097
     2098// Get USB bridge ID for "/dev/daX"
     2099static bool get_usb_id(const char * path, unsigned short & vendor_id,
     2100                       unsigned short & product_id, unsigned short & version)
     2101{
     2102  // Only "/dev/daX" supported
     2103  if (!(!strncmp(path, "/dev/da", 7) && !strchr(path + 7, '/')))
     2104    return false;
     2105   int bus = cam_getumassno((char *)path+5);
     2106   
     2107  if (bus == -1)
     2108    return false;
     2109
     2110  usbdevlist(bus,vendor_id,
     2111                       product_id, version);
     2112
     2113  return true;
     2114}
     2115
     2116
     2117smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
     2118{
     2119  int guess = parse_ata_chan_dev(name,NULL);
     2120  unsigned short vendor_id = 0, product_id = 0, version = 0;
     2121 
     2122  switch (guess) {
     2123  case CONTROLLER_ATA :
     2124    return new freebsd_ata_device(this, name, "");
     2125  case CONTROLLER_SCSI:
     2126    // Try to detect possible USB->(S)ATA bridge
     2127    if (get_usb_id(name, vendor_id, product_id, version)) {
     2128      const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
     2129      if (!usbtype)
     2130        return 0;
     2131      // Return SAT/USB device for this type
     2132      // (Note: freebsd_scsi_device::autodetect_open() will not be called in this case)
     2133      return get_sat_device(usbtype, new freebsd_scsi_device(this, name, ""));
     2134    }
     2135    // non usb device, handle as normal scsi
     2136    return new freebsd_scsi_device(this, name, "");
     2137  case CONTROLLER_CCISS:
     2138    // device - cciss, but no ID known
     2139    set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
     2140    return 0;
     2141  }
     2142 
     2143 
     2144  // TODO: Test autodetect device here
     2145  return 0;
     2146}
     2147
     2148
     2149smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
     2150{
     2151  // 3Ware ?
     2152  int disknum = -1, n1 = -1, n2 = -1;
     2153  if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
     2154    if (n2 != (int)strlen(type)) {
     2155      set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
     2156      return 0;
     2157    }
     2158    if (!(0 <= disknum && disknum <= 15)) {
     2159      set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15", disknum);
     2160      return 0;
     2161    }
     2162    int contr = parse_ata_chan_dev(name,NULL);
     2163    if (contr != CONTROLLER_3WARE_9000_CHAR && contr != CONTROLLER_3WARE_678K_CHAR)
     2164      contr = CONTROLLER_3WARE_678K;
     2165     return new freebsd_escalade_device(this, name, contr, disknum);
     2166  }
     2167
     2168  // Highpoint ?
     2169  int controller = -1, channel = -1; disknum = 1;
     2170  n1 = n2 = -1; int n3 = -1;
     2171  if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
     2172    int len = strlen(type);
     2173    if (!(n2 == len || n3 == len)) {
     2174      set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
     2175      return 0;
     2176    }
     2177    if (!(1 <= controller && controller <= 8)) {
     2178      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
     2179      return 0;
     2180    }
     2181    if (!(1 <= channel && channel <= 8)) {
     2182      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
     2183      return 0;
     2184    }
     2185    if (!(1 <= disknum && disknum <= 15)) {
     2186      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
     2187      return 0;
     2188    }
     2189    return new freebsd_highpoint_device(this, name, controller, channel, disknum);
     2190  }
     2191
     2192  // CCISS ?
     2193  disknum = n1 = n2 = -1;
     2194  if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
     2195    if (n2 != (int)strlen(type)) {
     2196      set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
     2197      return 0;
     2198    }
     2199    if (!(0 <= disknum && disknum <= 15)) {
     2200      set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 15", disknum);
     2201      return 0;
     2202    }
     2203    return new freebsd_cciss_device(this, name, disknum);
     2204  }
     2205
     2206  return 0;
     2207}
     2208
     2209const char * freebsd_smart_interface::get_valid_custom_dev_types_str()
     2210{
     2211  return "marvell, 3ware,N, hpt,L/M/N, cciss,N";
     2212}
     2213
     2214
     2215} // namespace
     2216
     2217
     2218/////////////////////////////////////////////////////////////////////////////
     2219/// Initialize platform interface and register with smi()
     2220
     2221void smart_interface::init()
     2222{
     2223  static os_freebsd::freebsd_smart_interface the_interface;
     2224  smart_interface::set(&the_interface);
     2225}