File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / os_freebsd.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:36:45 2012 UTC (11 years, 8 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_43, HEAD
smartmontools

    1: /*
    2:  * os_freebsd.c
    3:  *
    4:  * Home page of code is: http://smartmontools.sourceforge.net
    5:  *
    6:  * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net>
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 2, or (at your option)
   11:  * any later version.
   12:  *
   13:  * You should have received a copy of the GNU General Public License
   14:  * (for example COPYING); if not, write to the Free
   15:  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   16:  */
   17: 
   18: #include <stdio.h>
   19: #include <sys/types.h>
   20: #include <dirent.h>
   21: #include <fcntl.h>
   22: #include <err.h>
   23: #include <errno.h>
   24: #include <camlib.h>
   25: #include <cam/scsi/scsi_message.h>
   26: #include <cam/scsi/scsi_pass.h>
   27: #if defined(__DragonFly__)
   28: #include <sys/nata.h>
   29: #else
   30: #include <sys/ata.h>
   31: #endif
   32: #include <sys/stat.h>
   33: #include <unistd.h>
   34: #include <glob.h>
   35: #include <stddef.h>
   36: #include <paths.h>
   37: #include <sys/utsname.h>
   38: 
   39: #include "config.h"
   40: #include "int64.h"
   41: #include "atacmds.h"
   42: #include "scsicmds.h"
   43: #include "cciss.h"
   44: #include "utility.h"
   45: #include "os_freebsd.h"
   46: 
   47: #include "dev_interface.h"
   48: #include "dev_ata_cmd_set.h"
   49: 
   50: #define USBDEV "/dev/usb"
   51: #if defined(__FreeBSD_version)
   52: 
   53: // This way we define one variable for the GNU/kFreeBSD and FreeBSD 
   54: #define FREEBSDVER __FreeBSD_version
   55: #else
   56: #define FREEBSDVER __FreeBSD_kernel_version
   57: #endif
   58: 
   59: #if (FREEBSDVER >= 800000)
   60: #include <libusb20_desc.h>
   61: #include <libusb20.h>
   62: #elif defined(__DragonFly__)
   63: #include <bus/usb/usb.h>
   64: #include <bus/usb/usbhid.h>
   65: #else
   66: #include <dev/usb/usb.h>
   67: #include <dev/usb/usbhid.h>
   68: #endif
   69: 
   70: #define CONTROLLER_3WARE_9000_CHAR      0x01
   71: #define CONTROLLER_3WARE_678K_CHAR      0x02
   72: 
   73: #ifndef PATHINQ_SETTINGS_SIZE
   74: #define PATHINQ_SETTINGS_SIZE   128
   75: #endif
   76: 
   77: const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp,v 1.1.1.2 2012/10/09 09:36:45 misho Exp $" \
   78: ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
   79: 
   80: #define NO_RETURN 0
   81: #define BAD_SMART 1
   82: #define NO_DISK_3WARE 2
   83: #define BAD_KERNEL 3
   84: #define MAX_MSG 3
   85: 
   86: // Utility function for printing warnings
   87: void printwarning(int msgNo, const char* extra) {
   88:   static int printed[] = {0,0,0,0};
   89:   static const char* message[]={
   90:     "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",
   91: 
   92:     "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
   93: 
   94:     "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
   95: 
   96:     "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
   97:   };
   98: 
   99:   if (msgNo >= 0 && msgNo <= MAX_MSG) {
  100:     if (!printed[msgNo]) {
  101:       printed[msgNo] = 1;
  102:       pout("%s", message[msgNo]);
  103:       if (extra)
  104:         pout("%s",extra);
  105:     }
  106:   }
  107:   return;
  108: }
  109: 
  110: // Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
  111: 
  112: #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
  113: #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
  114: #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
  115: 
  116: #ifndef ATA_DEVICE
  117: #define ATA_DEVICE "/dev/ata"
  118: #endif
  119: 
  120: #define ARGUSED(x) ((void)(x))
  121: 
  122: // global variable holding byte count of allocated memory
  123: long long bytes;
  124: 
  125: /////////////////////////////////////////////////////////////////////////////
  126: 
  127: namespace os_freebsd { // No need to publish anything, name provided for Doxygen
  128: 
  129: /////////////////////////////////////////////////////////////////////////////
  130: /// Implement shared open/close routines with old functions.
  131: 
  132: class freebsd_smart_device
  133: : virtual public /*implements*/ smart_device
  134: {
  135: public:
  136:   explicit freebsd_smart_device(const char * mode)
  137:     : smart_device(never_called),
  138:       m_fd(-1), m_mode(mode) { }
  139: 
  140:   virtual ~freebsd_smart_device() throw();
  141: 
  142:   virtual bool is_open() const;
  143: 
  144:   virtual bool open();
  145: 
  146:   virtual bool close();
  147: 
  148: protected:
  149:   /// Return filedesc for derived classes.
  150:   int get_fd() const
  151:     { return m_fd; }
  152: 
  153:   void set_fd(int fd)
  154:     { m_fd = fd; }
  155: 
  156: private:
  157:   int m_fd; ///< filedesc, -1 if not open.
  158:   const char * m_mode; ///< Mode string for deviceopen().
  159: };
  160: 
  161: #ifdef __GLIBC__
  162: static inline void * reallocf(void *ptr, size_t size) {
  163:    void *rv = realloc(ptr, size);
  164:    if((rv == NULL) && (size != 0))
  165:      free(ptr);
  166:    return rv;
  167:    }
  168: #endif
  169: 
  170: freebsd_smart_device::~freebsd_smart_device() throw()
  171: {
  172:   if (m_fd >= 0)
  173:     os_freebsd::freebsd_smart_device::close();
  174: }
  175: 
  176: // migration from the old_style 
  177: unsigned char m_controller_type;
  178: unsigned char m_controller_port; 
  179: 
  180: // examples for smartctl
  181: static const char  smartctl_examples[] =
  182:    "=================================================== SMARTCTL EXAMPLES =====\n\n"
  183:          "  smartctl -a /dev/ad0                       (Prints all SMART information)\n\n"
  184:          "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
  185:          "                                              (Enables SMART on first disk)\n\n"
  186:          "  smartctl -t long /dev/ad0              (Executes extended disk self-test)\n\n"
  187:          "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
  188:          "                                      (Prints Self-Test & Attribute errors)\n"
  189:          "                                      (Prints Self-Test & Attribute errors)\n\n"
  190:          "  smartctl -a --device=3ware,2 /dev/twa0\n"
  191:          "  smartctl -a --device=3ware,2 /dev/twe0\n"
  192:          "                              (Prints all SMART information for ATA disk on\n"
  193:          "                                 third port of first 3ware RAID controller)\n"
  194:   "  smartctl -a --device=cciss,0 /dev/ciss0\n"
  195:          "                              (Prints all SMART information for first disk \n"
  196:          "                               on Common Interface for SCSI-3 Support driver)\n"
  197:   "  smartctl -a --device=areca,3/1 /dev/arcmsr0\n"
  198:          "                              (Prints all SMART information for 3rd disk in the 1st enclosure \n"
  199:          "                               on first ARECA RAID controller)\n"
  200: 
  201:          ;
  202: 
  203: bool freebsd_smart_device::is_open() const
  204: {
  205:   return (m_fd >= 0);
  206: }
  207: 
  208: 
  209: bool freebsd_smart_device::open()
  210: {
  211:   const char *dev = get_dev_name();
  212:   if ((m_fd = ::open(dev,O_RDONLY))<0) {
  213:     set_err(errno);
  214:     return false;
  215:   }
  216:   return true;
  217: }
  218: 
  219: bool freebsd_smart_device::close()
  220: {
  221:   int failed = 0;
  222:   // close device, if open
  223:   if (is_open())
  224:     failed=::close(get_fd());
  225: 
  226:   set_fd(-1);
  227: 
  228:   if(failed) return false;
  229:     else return true;
  230: }
  231: 
  232: /////////////////////////////////////////////////////////////////////////////
  233: /// Implement standard ATA support
  234: 
  235: class freebsd_ata_device
  236: : public /*implements*/ ata_device,
  237:   public /*extends*/ freebsd_smart_device
  238: {
  239: public:
  240:   freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
  241:   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
  242: 
  243: protected:
  244:   virtual int do_cmd(struct ata_ioc_request* request, bool is_48bit_cmd);
  245: };
  246: 
  247: freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
  248: : smart_device(intf, dev_name, "ata", req_type),
  249:   freebsd_smart_device("ATA")
  250: {
  251: }
  252: 
  253: int freebsd_ata_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd)
  254: {
  255:   int fd = get_fd();
  256:   ARGUSED(is_48bit_cmd); // no support for 48 bit commands in the IOCATAREQUEST
  257:   return ioctl(fd, IOCATAREQUEST, request);
  258: }
  259: 
  260: 
  261: 
  262: bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
  263: {
  264:   bool ata_48bit = false; // no ata_48bit_support via IOCATAREQUEST
  265:   if(!strcmp("atacam",get_dev_type())) // enable for atacam interface
  266:     ata_48bit = true;
  267: 
  268:   if (!ata_cmd_is_ok(in,
  269:     true,  // data_out_support
  270:     true,  // multi_sector_support
  271:     ata_48bit) 
  272:     ) 
  273:     return false;
  274: 
  275:   struct ata_ioc_request request;
  276:   bzero(&request,sizeof(struct ata_ioc_request));
  277: 
  278:   request.timeout=SCSI_TIMEOUT_DEFAULT;
  279:   request.u.ata.command=in.in_regs.command;
  280:   request.u.ata.feature=in.in_regs.features;
  281: 
  282:   request.u.ata.count = in.in_regs.sector_count_16;
  283:   request.u.ata.lba = in.in_regs.lba_48;
  284: 
  285:   switch (in.direction) {
  286:     case ata_cmd_in::no_data:  
  287:       request.flags=ATA_CMD_CONTROL;
  288:       break;
  289:     case ata_cmd_in::data_in:  
  290:       request.flags=ATA_CMD_READ | ATA_CMD_CONTROL;
  291:       request.data=(char *)in.buffer;
  292:       request.count=in.size;
  293:       break;
  294:     case ata_cmd_in::data_out: 
  295:       request.flags=ATA_CMD_WRITE | ATA_CMD_CONTROL;
  296:       request.data=(char *)in.buffer;
  297:       request.count=in.size;
  298:       break;
  299:     default:
  300:       return set_err(ENOSYS);
  301:   }
  302: 
  303:   clear_err();
  304:   errno = 0;
  305:   if (do_cmd(&request, in.in_regs.is_48bit_cmd()))
  306:       return set_err(errno);
  307:   if (request.error)
  308:       return set_err(EIO, "request failed, error code 0x%02x", request.error);
  309: 
  310:   out.out_regs.error = request.error;
  311:   out.out_regs.sector_count_16 = request.u.ata.count;
  312:   out.out_regs.lba_48 = request.u.ata.lba;
  313: 
  314: 
  315:   // Command specific processing
  316:   if (in.in_regs.command == ATA_SMART_CMD
  317:        && in.in_regs.features == ATA_SMART_STATUS
  318:        && in.out_needed.lba_high)
  319:   {
  320:     unsigned const char normal_lo=0x4f, normal_hi=0xc2;
  321:     unsigned const char failed_lo=0xf4, failed_hi=0x2c;
  322: 
  323:     // Cyl low and Cyl high unchanged means "Good SMART status"
  324:     if (!(out.out_regs.lba_mid==normal_lo && out.out_regs.lba_high==normal_hi)
  325:     // These values mean "Bad SMART status"
  326:         && !(out.out_regs.lba_mid==failed_lo && out.out_regs.lba_high==failed_hi))
  327: 
  328:     {
  329:       // We haven't gotten output that makes sense; print out some debugging info
  330:       char buf[512];
  331:       sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
  332:         (int)request.u.ata.command,
  333:         (int)request.u.ata.feature,
  334:         (int)request.u.ata.count,
  335:         (int)((request.u.ata.lba) & 0xff),
  336:         (int)((request.u.ata.lba>>8) & 0xff),
  337:         (int)((request.u.ata.lba>>16) & 0xff),
  338:         (int)request.error);
  339:       printwarning(BAD_SMART,buf);
  340:       out.out_regs.lba_high = failed_hi; 
  341:       out.out_regs.lba_mid = failed_lo;
  342:     }
  343:   }
  344: 
  345:   return true;
  346: }
  347: 
  348: #if FREEBSDVER > 800100
  349: class freebsd_atacam_device : public freebsd_ata_device
  350: {
  351: public:
  352:   freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type)
  353:   : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type)
  354:   {}
  355:   
  356:   virtual bool open();
  357:   virtual bool close();
  358:   
  359: protected:
  360:   int m_fd;
  361:   struct cam_device *m_camdev;
  362: 
  363:   virtual int do_cmd( struct ata_ioc_request* request , bool is_48bit_cmd);
  364: };
  365: 
  366: bool freebsd_atacam_device::open(){
  367:   const char *dev = get_dev_name();
  368:   
  369:   if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
  370:     set_err(errno);
  371:     return false;
  372:   }
  373:   set_fd(m_camdev->fd);
  374:   return true;
  375: }
  376: 
  377: bool freebsd_atacam_device::close(){
  378:   cam_close_device(m_camdev);
  379:   set_fd(-1);
  380:   return true;
  381: }
  382: 
  383: int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd)
  384: {
  385:   union ccb ccb;
  386:   int camflags;
  387: 
  388:   memset(&ccb, 0, sizeof(ccb));
  389: 
  390:   if (request->count == 0)
  391:     camflags = CAM_DIR_NONE;
  392:   else if (request->flags & ATA_CMD_READ)
  393:     camflags = CAM_DIR_IN;
  394:   else
  395:     camflags = CAM_DIR_OUT;
  396:   if(is_48bit_cmd)
  397:     camflags |= CAM_ATAIO_48BIT;
  398: 
  399:   cam_fill_ataio(&ccb.ataio,
  400:                  0,
  401:                  NULL,
  402:                  camflags,
  403:                  MSG_SIMPLE_Q_TAG,
  404:                  (u_int8_t*)request->data,
  405:                  request->count,
  406:                  request->timeout * 1000); // timeout in seconds
  407: 
  408:   ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT;
  409:   // ata_28bit_cmd
  410:   ccb.ataio.cmd.command = request->u.ata.command;
  411:   ccb.ataio.cmd.features = request->u.ata.feature;
  412:   ccb.ataio.cmd.lba_low = request->u.ata.lba;
  413:   ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8;
  414:   ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16;
  415:   // ata_48bit cmd
  416:   ccb.ataio.cmd.lba_low_exp = request->u.ata.lba >> 24;
  417:   ccb.ataio.cmd.lba_mid_exp = request->u.ata.lba >> 32;
  418:   ccb.ataio.cmd.lba_high_exp = request->u.ata.lba >> 40;
  419:   ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f);
  420:   ccb.ataio.cmd.sector_count = request->u.ata.count;
  421:   ccb.ataio.cmd.sector_count_exp = request->u.ata.count  >> 8;;
  422: 
  423:   ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
  424: 
  425:   if (cam_send_ccb(m_camdev, &ccb) < 0) {
  426:     err(1, "cam_send_ccb");
  427:     return -1;
  428:   }
  429: 
  430:   if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  431:     cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
  432:     return -1;
  433:   }
  434: 
  435:   request->u.ata.lba =
  436:     ((u_int64_t)(ccb.ataio.res.lba_low)) |
  437:     ((u_int64_t)(ccb.ataio.res.lba_mid) << 8) |
  438:     ((u_int64_t)(ccb.ataio.res.lba_high) << 16) |
  439:     ((u_int64_t)(ccb.ataio.res.lba_low_exp) << 24) |
  440:     ((u_int64_t)(ccb.ataio.res.lba_mid_exp) << 32) |
  441:     ((u_int64_t)(ccb.ataio.res.lba_high_exp) << 40);
  442: 
  443:   request->u.ata.count = ccb.ataio.res.sector_count | (ccb.ataio.res.sector_count_exp << 8);
  444:   request->error = ccb.ataio.res.error;
  445: 
  446:   return 0;
  447: }
  448: 
  449: #endif
  450: 
  451: /////////////////////////////////////////////////////////////////////////////
  452: /// Implement AMCC/3ware RAID support with old functions
  453: 
  454: class freebsd_escalade_device
  455: : public /*implements*/ ata_device_with_command_set,
  456:   public /*extends*/ freebsd_smart_device
  457: {
  458: public:
  459:   freebsd_escalade_device(smart_interface * intf, const char * dev_name,
  460:     int escalade_type, int disknum);
  461: 
  462: protected:
  463:   virtual int ata_command_interface(smart_command_set command, int select, char * data);
  464:   virtual bool open();
  465: 
  466: private:
  467:   int m_escalade_type; ///< Type string for escalade_command_interface().
  468:   int m_disknum; ///< Disk number.
  469: };
  470: 
  471: freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name,
  472:     int escalade_type, int disknum)
  473: : smart_device(intf, dev_name, "3ware", "3ware"),
  474:   freebsd_smart_device(
  475:     escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" :
  476:     escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" :
  477:     /*             CONTROLLER_3WARE_678K     */ "ATA"             ),
  478:   m_escalade_type(escalade_type), m_disknum(disknum)
  479: {
  480:   set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
  481: }
  482: 
  483: bool freebsd_escalade_device::open()
  484: {
  485:   const char *dev = get_dev_name();
  486:   int fd;
  487:   
  488:   if ((fd = ::open(dev,O_RDWR))<0) {
  489:     set_err(errno);
  490:     return false;
  491:   }
  492:   set_fd(fd);
  493:   return true;
  494: }
  495: 
  496: int freebsd_escalade_device::ata_command_interface(smart_command_set command, int select, char * data)
  497: {
  498:   // to hold true file descriptor
  499:   int fd = get_fd();
  500: 
  501:   // return value and buffer for ioctl()
  502:   int  ioctlreturn, readdata=0;
  503:   struct twe_usercommand* cmd_twe = NULL;
  504:   TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
  505:   TWE_Command_ATA* ata = NULL;
  506: 
  507:   // Used by both the SCSI and char interfaces
  508:   char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
  509: 
  510:   if (m_disknum < 0) {
  511:     printwarning(NO_DISK_3WARE,NULL);
  512:     return -1;
  513:   }
  514: 
  515:   memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
  516: 
  517:   if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
  518:     cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
  519:     cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
  520:     cmd_twa->driver_pkt.buffer_length = 512;
  521:     ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
  522:   } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
  523:     cmd_twe = (struct twe_usercommand*)ioctl_buffer;
  524:     ata = &cmd_twe->tu_command.ata;
  525:   } else {
  526:     pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
  527:       "Please contact " PACKAGE_BUGREPORT "\n", m_escalade_type, m_disknum);
  528:     errno=ENOSYS;
  529:     return -1;
  530:   }
  531: 
  532:   ata->opcode = TWE_OP_ATA_PASSTHROUGH;
  533: 
  534:   // Same for (almost) all commands - but some reset below
  535:   ata->request_id    = 0xFF;
  536:   ata->unit          = m_disknum;
  537:   ata->status        = 0;           
  538:   ata->flags         = 0x1;
  539:   ata->drive_head    = 0x0;
  540:   ata->sector_num    = 0;
  541: 
  542:   // All SMART commands use this CL/CH signature.  These are magic
  543:   // values from the ATA specifications.
  544:   ata->cylinder_lo   = 0x4F;
  545:   ata->cylinder_hi   = 0xC2;
  546: 
  547:   // SMART ATA COMMAND REGISTER value
  548:   ata->command       = ATA_SMART_CMD;
  549: 
  550:   // Is this a command that reads or returns 512 bytes?
  551:   // passthru->param values are:
  552:   // 0x0 - non data command without TFR write check,
  553:   // 0x8 - non data command with TFR write check,
  554:   // 0xD - data command that returns data to host from device
  555:   // 0xF - data command that writes data from host to device
  556:   // passthru->size values are 0x5 for non-data and 0x07 for data
  557:   if (command == READ_VALUES     ||
  558:       command == READ_THRESHOLDS ||
  559:       command == READ_LOG        ||
  560:       command == IDENTIFY        ||
  561:       command == WRITE_LOG ) 
  562:   {
  563:     readdata=1;
  564:     if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
  565:       cmd_twe->tu_data = data;
  566:       cmd_twe->tu_size = 512;
  567:     }
  568:     ata->sgl_offset = 0x5;
  569:     ata->size         = 0x5;
  570:     ata->param        = 0xD;
  571:     ata->sector_count = 0x1;
  572:     // For 64-bit to work correctly, up the size of the command packet
  573:     // in dwords by 1 to account for the 64-bit single sgl 'address'
  574:     // field. Note that this doesn't agree with the typedefs but it's
  575:     // right (agree with kernel driver behavior/typedefs).
  576:     //if (sizeof(long)==8)
  577:     //  ata->size++;
  578:   }
  579:   else {
  580:     // Non data command -- but doesn't use large sector 
  581:     // count register values.  
  582:     ata->sgl_offset = 0x0;
  583:     ata->size         = 0x5;
  584:     ata->param        = 0x8;
  585:     ata->sector_count = 0x0;
  586:   }
  587: 
  588:   // Now set ATA registers depending upon command
  589:   switch (command){
  590:   case CHECK_POWER_MODE:
  591:     ata->command     = ATA_CHECK_POWER_MODE;
  592:     ata->features    = 0;
  593:     ata->cylinder_lo = 0;
  594:     ata->cylinder_hi = 0;
  595:     break;
  596:   case READ_VALUES:
  597:     ata->features = ATA_SMART_READ_VALUES;
  598:     break;
  599:   case READ_THRESHOLDS:
  600:     ata->features = ATA_SMART_READ_THRESHOLDS;
  601:     break;
  602:   case READ_LOG:
  603:     ata->features = ATA_SMART_READ_LOG_SECTOR;
  604:     // log number to return
  605:     ata->sector_num  = select;
  606:     break;
  607:   case WRITE_LOG:
  608:     readdata=0;
  609:     ata->features     = ATA_SMART_WRITE_LOG_SECTOR;
  610:     ata->sector_count = 1;
  611:     ata->sector_num   = select;
  612:     ata->param        = 0xF;  // PIO data write
  613:     break;
  614:   case IDENTIFY:
  615:     // ATA IDENTIFY DEVICE
  616:     ata->command     = ATA_IDENTIFY_DEVICE;
  617:     ata->features    = 0;
  618:     ata->cylinder_lo = 0;
  619:     ata->cylinder_hi = 0;
  620:     break;
  621:   case PIDENTIFY:
  622:     // 3WARE controller can NOT have packet device internally
  623:     pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum);
  624:     errno=ENODEV;
  625:     return -1;
  626:   case ENABLE:
  627:     ata->features = ATA_SMART_ENABLE;
  628:     break;
  629:   case DISABLE:
  630:     ata->features = ATA_SMART_DISABLE;
  631:     break;
  632:   case AUTO_OFFLINE:
  633:     ata->features     = ATA_SMART_AUTO_OFFLINE;
  634:     // Enable or disable?
  635:     ata->sector_count = select;
  636:     break;
  637:   case AUTOSAVE:
  638:     ata->features     = ATA_SMART_AUTOSAVE;
  639:     // Enable or disable?
  640:     ata->sector_count = select;
  641:     break;
  642:   case IMMEDIATE_OFFLINE:
  643:     ata->features    = ATA_SMART_IMMEDIATE_OFFLINE;
  644:     // What test type to run?
  645:     ata->sector_num  = select;
  646:     break;
  647:   case STATUS_CHECK:
  648:     ata->features = ATA_SMART_STATUS;
  649:     break;
  650:   case STATUS:
  651:     // This is JUST to see if SMART is enabled, by giving SMART status
  652:     // command. But it doesn't say if status was good, or failing.
  653:     // See below for the difference.
  654:     ata->features = ATA_SMART_STATUS;
  655:     break;
  656:   default:
  657:     pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
  658:          "Please contact " PACKAGE_BUGREPORT "\n", command, m_disknum);
  659:     errno=ENOSYS;
  660:     return -1;
  661:   }
  662: 
  663:   // Now send the command down through an ioctl()
  664:   if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
  665:     ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
  666:   } else {
  667:     ioctlreturn=ioctl(fd,TWEIO_COMMAND,cmd_twe);
  668:   }
  669: 
  670:   // Deal with the different error cases
  671:   if (ioctlreturn) {
  672:     if (!errno)
  673:       errno=EIO;
  674:     return -1;
  675:   }
  676: 
  677:   // See if the ATA command failed.  Now that we have returned from
  678:   // the ioctl() call, if passthru is valid, then:
  679:   // - ata->status contains the 3ware controller STATUS
  680:   // - ata->command contains the ATA STATUS register
  681:   // - ata->features contains the ATA ERROR register
  682:   //
  683:   // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
  684:   // If bit 0 (error bit) is set, then ATA ERROR register is valid.
  685:   // While we *might* decode the ATA ERROR register, at the moment it
  686:   // doesn't make much sense: we don't care in detail why the error
  687:   // happened.
  688: 
  689:   if (ata->status || (ata->command & 0x21)) {
  690:     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);
  691:     errno=EIO;
  692:     return -1;
  693:   }
  694: 
  695:   // If this is a read data command, copy data to output buffer
  696:   if (readdata) {
  697:     if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR)
  698:       memcpy(data, cmd_twa->pdata, 512);
  699:   }
  700: 
  701:   // For STATUS_CHECK, we need to check register values
  702:   if (command==STATUS_CHECK) {
  703: 
  704:     // To find out if the SMART RETURN STATUS is good or failing, we
  705:     // need to examine the values of the Cylinder Low and Cylinder
  706:     // High Registers.
  707: 
  708:     unsigned short cyl_lo=ata->cylinder_lo;
  709:     unsigned short cyl_hi=ata->cylinder_hi;
  710: 
  711:     // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
  712:     if (cyl_lo==0x4F && cyl_hi==0xC2)
  713:       return 0;
  714: 
  715:     // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
  716:     if (cyl_lo==0xF4 && cyl_hi==0x2C)
  717:       return 1;
  718: 
  719:       errno=EIO;
  720:       return -1;
  721:   }
  722: 
  723:   // copy sector count register (one byte!) to return data
  724:   if (command==CHECK_POWER_MODE)
  725:     *data=*(char *)&(ata->sector_count);
  726: 
  727:   // look for nonexistent devices/ports
  728:   if (command==IDENTIFY && !nonempty(data, 512)) {
  729:     errno=ENODEV;
  730:     return -1;
  731:   }
  732: 
  733:   return 0;
  734: }
  735: 
  736: 
  737: /////////////////////////////////////////////////////////////////////////////
  738: /// Implement Highpoint RAID support with old functions
  739: 
  740: class freebsd_highpoint_device
  741: : public /*implements*/ ata_device_with_command_set,
  742:   public /*extends*/ freebsd_smart_device
  743: {
  744: public:
  745:   freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
  746:     unsigned char controller, unsigned char channel, unsigned char port);
  747: 
  748: protected:
  749:   virtual int ata_command_interface(smart_command_set command, int select, char * data);
  750:   virtual bool open();
  751: 
  752: private:
  753:   unsigned char m_hpt_data[3]; ///< controller/channel/port
  754: };
  755: 
  756: 
  757: freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
  758:   unsigned char controller, unsigned char channel, unsigned char port)
  759: : smart_device(intf, dev_name, "hpt", "hpt"),
  760:   freebsd_smart_device("ATA")
  761: {
  762:   m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port;
  763:   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]);
  764: }
  765: 
  766: bool freebsd_highpoint_device::open()
  767: {
  768:   const char *dev = get_dev_name();
  769:   int fd;
  770:   
  771:   if ((fd = ::open(dev,O_RDWR))<0) {
  772:     set_err(errno);
  773:     return false;
  774:   }
  775:   set_fd(fd);
  776:   return true;
  777: }
  778: 
  779: int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
  780: {
  781:   int fd=get_fd(); 
  782:   int ids[2];
  783:   HPT_IOCTL_PARAM param;
  784:   HPT_CHANNEL_INFO_V2 info;
  785:   unsigned char* buff[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)];
  786:   PHPT_PASS_THROUGH_HEADER pide_pt_hdr, pide_pt_hdr_out;
  787: 
  788:   // get internal deviceid
  789:   ids[0] = m_hpt_data[0] - 1;
  790:   ids[1] = m_hpt_data[1] - 1;
  791: 
  792:   memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
  793: 
  794:   param.magic = HPT_IOCTL_MAGIC;
  795:   param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO_V2;
  796:   param.in = (unsigned char *)ids;
  797:   param.in_size = sizeof(unsigned int) * 2;
  798:   param.out = (unsigned char *)&info;
  799:   param.out_size = sizeof(HPT_CHANNEL_INFO_V2);
  800: 
  801:   if (m_hpt_data[2]==1) {
  802:     param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO;
  803:     param.out_size = sizeof(HPT_CHANNEL_INFO);
  804:   }
  805:   if (ioctl(fd, HPT_DO_IOCONTROL, &param)!=0 ||
  806:       info.devices[m_hpt_data[2]-1]==0) {
  807:     return -1;
  808:   }
  809: 
  810:   // perform smart action
  811:   memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER));
  812:   pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff;
  813: 
  814:   pide_pt_hdr->lbamid = 0x4f;
  815:   pide_pt_hdr->lbahigh = 0xc2;
  816:   pide_pt_hdr->command = ATA_SMART_CMD;
  817:   pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1];
  818: 
  819:   switch (command){
  820:   case READ_VALUES:
  821:     pide_pt_hdr->feature=ATA_SMART_READ_VALUES;
  822:     pide_pt_hdr->protocol=HPT_READ;
  823:     break;
  824:   case READ_THRESHOLDS:
  825:     pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS;
  826:     pide_pt_hdr->protocol=HPT_READ;
  827:     break;
  828:   case READ_LOG:
  829:     pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR;
  830:     pide_pt_hdr->lbalow=select;
  831:     pide_pt_hdr->protocol=HPT_READ;
  832:     break;
  833:   case IDENTIFY:
  834:     pide_pt_hdr->command=ATA_IDENTIFY_DEVICE;
  835:     pide_pt_hdr->protocol=HPT_READ;
  836:     break;
  837:   case ENABLE:
  838:     pide_pt_hdr->feature=ATA_SMART_ENABLE;
  839:     break;
  840:   case DISABLE:
  841:     pide_pt_hdr->feature=ATA_SMART_DISABLE;
  842:     break;
  843:   case AUTO_OFFLINE:
  844:     pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE;
  845:     pide_pt_hdr->sectorcount=select;
  846:     break;
  847:   case AUTOSAVE:
  848:     pide_pt_hdr->feature=ATA_SMART_AUTOSAVE;
  849:     pide_pt_hdr->sectorcount=select;
  850:     break;
  851:   case IMMEDIATE_OFFLINE:
  852:     pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE;
  853:     pide_pt_hdr->lbalow=select;
  854:     break;
  855:   case STATUS_CHECK:
  856:   case STATUS:
  857:     pide_pt_hdr->feature=ATA_SMART_STATUS;
  858:     break;
  859:   case CHECK_POWER_MODE:
  860:     pide_pt_hdr->command=ATA_CHECK_POWER_MODE;
  861:     break;
  862:   case WRITE_LOG:
  863:     memcpy(buff+sizeof(HPT_PASS_THROUGH_HEADER), data, 512);
  864:     pide_pt_hdr->feature=ATA_SMART_WRITE_LOG_SECTOR;
  865:     pide_pt_hdr->lbalow=select;
  866:     pide_pt_hdr->protocol=HPT_WRITE;
  867:     break;
  868:   default:
  869:     pout("Unrecognized command %d in highpoint_command_interface()\n"
  870:          "Please contact " PACKAGE_BUGREPORT "\n", command);
  871:     errno=ENOSYS;
  872:     return -1;
  873:   }
  874:   if (pide_pt_hdr->protocol!=0) {
  875:     pide_pt_hdr->sectors = 1;
  876:     pide_pt_hdr->sectorcount = 1;
  877:   }
  878: 
  879:   memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
  880: 
  881:   param.magic = HPT_IOCTL_MAGIC;
  882:   param.ctrl_code = HPT_IOCTL_IDE_PASS_THROUGH;
  883:   param.in = (unsigned char *)buff;
  884:   param.in_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? 0 : pide_pt_hdr->sectors * 512);
  885:   param.out = (unsigned char *)buff+param.in_size;
  886:   param.out_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? pide_pt_hdr->sectors * 512 : 0);
  887: 
  888:   pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out;
  889: 
  890:   if ((ioctl(fd, HPT_DO_IOCONTROL, &param)!=0) ||
  891:       (pide_pt_hdr_out->command & 1)) {
  892:     return -1;
  893:   }
  894: 
  895:   if (command==STATUS_CHECK)
  896:   {
  897:     unsigned const char normal_lo=0x4f, normal_hi=0xc2;
  898:     unsigned const char failed_lo=0xf4, failed_hi=0x2c;
  899:     unsigned char low,high;
  900: 
  901:     high = pide_pt_hdr_out->lbahigh;
  902:     low = pide_pt_hdr_out->lbamid;
  903: 
  904:     // Cyl low and Cyl high unchanged means "Good SMART status"
  905:     if (low==normal_lo && high==normal_hi)
  906:       return 0;
  907: 
  908:     // These values mean "Bad SMART status"
  909:     if (low==failed_lo && high==failed_hi)
  910:       return 1;
  911: 
  912:     // We haven't gotten output that makes sense; print out some debugging info
  913:     char buf[512];
  914:     sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
  915:             (int)pide_pt_hdr_out->command,
  916:             (int)pide_pt_hdr_out->feature,
  917:             (int)pide_pt_hdr_out->sectorcount,
  918:             (int)pide_pt_hdr_out->lbalow,
  919:             (int)pide_pt_hdr_out->lbamid,
  920:             (int)pide_pt_hdr_out->lbahigh,
  921:             (int)pide_pt_hdr_out->sectors);
  922:     printwarning(BAD_SMART,buf);
  923:   }
  924:   else if (command==CHECK_POWER_MODE)
  925:     data[0] = pide_pt_hdr_out->sectorcount & 0xff;
  926:   else if (pide_pt_hdr->protocol==HPT_READ)
  927:     memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER), 
  928:       pide_pt_hdr->sectors * 512);
  929:   return 0;
  930: }
  931: 
  932: 
  933: /////////////////////////////////////////////////////////////////////////////
  934: /// Standard SCSI support
  935: 
  936: class freebsd_scsi_device
  937: : public /*implements*/ scsi_device,
  938:   public /*extends*/ freebsd_smart_device
  939: {
  940: public:
  941:   freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
  942: 
  943:   virtual smart_device * autodetect_open();
  944: 
  945:   virtual bool scsi_pass_through(scsi_cmnd_io * iop);
  946:   
  947:   virtual bool open();
  948: 
  949:   virtual bool close();
  950:   
  951: private:
  952:   int m_fd;
  953:   struct cam_device *m_camdev;
  954: };
  955: 
  956: bool freebsd_scsi_device::open(){
  957:   const char *dev = get_dev_name();
  958:   
  959:   if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
  960:     set_err(errno);
  961:     return false;
  962:   }
  963:   set_fd(m_camdev->fd);
  964:   return true;
  965: }
  966: 
  967: bool freebsd_scsi_device::close(){
  968:   cam_close_device(m_camdev);
  969:   set_fd(-1);
  970:   return true;
  971: }
  972: 
  973: freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
  974:   const char * dev_name, const char * req_type)
  975: : smart_device(intf, dev_name, "scsi", req_type),
  976:   freebsd_smart_device("SCSI")
  977: {
  978: }
  979: 
  980: 
  981: bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
  982: {
  983:   int report=scsi_debugmode;
  984:   union ccb *ccb;
  985: 
  986:   if (report > 0) {
  987:     unsigned int k;
  988:     const unsigned char * ucp = iop->cmnd;
  989:     const char * np;
  990: 
  991:     np = scsi_get_opcode_name(ucp[0]);
  992:     pout(" [%s: ", np ? np : "<unknown opcode>");
  993:     for (k = 0; k < iop->cmnd_len; ++k)
  994:       pout("%02x ", ucp[k]);
  995:     if ((report > 1) && 
  996:       (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
  997:     int trunc = (iop->dxfer_len > 256) ? 1 : 0;
  998: 
  999:     pout("]\n  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
 1000:       (trunc ? " [only first 256 bytes shown]" : ""));
 1001:     dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
 1002:       }
 1003:       else
 1004:         pout("]");
 1005:   }
 1006: 
 1007:   if(m_camdev==NULL) {
 1008:     warnx("error: camdev=0!");
 1009:     return -ENOTTY;
 1010:   }
 1011: 
 1012:   if (!(ccb = cam_getccb(m_camdev))) {
 1013:     warnx("error allocating ccb");
 1014:     return -ENOMEM;
 1015:   }
 1016:   // mfi SAT layer is known to be buggy
 1017:   if(!strcmp("mfi",m_camdev->sim_name)) {
 1018:     if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { 
 1019:       // Controller does not return ATA output registers in SAT sense data
 1020:       if (iop->cmnd[2] & (1 << 5)) // chk_cond
 1021:         return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware");
 1022:     }
 1023:     // SMART WRITE LOG SECTOR causing media errors
 1024:     if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 && iop->cmnd[14] == ATA_SMART_CMD 
 1025:         && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || 
 1026:         (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 && iop->cmnd[9] == ATA_SMART_CMD &&
 1027:         iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) 
 1028:       return set_err(ENOSYS, "SMART WRITE LOG SECTOR command is not supported by controller firmware"); 
 1029:   }
 1030: 
 1031:   // clear out structure, except for header that was filled in for us
 1032:   bzero(&(&ccb->ccb_h)[1],
 1033:     sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
 1034: 
 1035:   cam_fill_csio(&ccb->csio,
 1036:     /*retrires*/ 1,
 1037:     /*cbfcnp*/ NULL,
 1038:     /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)),
 1039:     /* tagaction */ MSG_SIMPLE_Q_TAG,
 1040:     /* dataptr */ iop->dxferp,
 1041:     /* datalen */ iop->dxfer_len,
 1042:     /* senselen */ iop->max_sense_len,
 1043:     /* cdblen */ iop->cmnd_len,
 1044:     /* timout (converted to seconds) */ iop->timeout*1000);
 1045:   memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len);
 1046: 
 1047:   if (cam_send_ccb(m_camdev,ccb) < 0) {
 1048:     warn("error sending SCSI ccb");
 1049:     cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
 1050:     cam_freeccb(ccb);
 1051:     return -EIO;
 1052:   }
 1053: 
 1054:   if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) {
 1055:     cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
 1056:     cam_freeccb(ccb);
 1057:     return -EIO;
 1058:   }
 1059: 
 1060:   if (iop->sensep) {
 1061:     iop->resp_sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
 1062:     memcpy(iop->sensep,&(ccb->csio.sense_data),iop->resp_sense_len);
 1063:   }
 1064: 
 1065:   iop->scsi_status = ccb->csio.scsi_status;
 1066: 
 1067:   cam_freeccb(ccb);
 1068: 
 1069:   if (report > 0) {
 1070:     int trunc;
 1071: 
 1072:     pout("  status=0\n");
 1073:     trunc = (iop->dxfer_len > 256) ? 1 : 0;
 1074: 
 1075:     pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
 1076:       (trunc ? " [only first 256 bytes shown]" : ""));
 1077:     dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
 1078:   }
 1079: 
 1080:   return true;
 1081: }
 1082: 
 1083: 
 1084: /////////////////////////////////////////////////////////////////////////////
 1085: /// Areca RAID support
 1086: 
 1087: class freebsd_areca_device
 1088: : public /*implements*/ ata_device,
 1089:   public /*extends*/ freebsd_smart_device
 1090: {
 1091: public:
 1092:   freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
 1093: 
 1094: protected:
 1095:   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 
 1096: 
 1097: private:
 1098:   int m_disknum; ///< Disk number.
 1099:   int m_encnum;
 1100: };
 1101: 
 1102: 
 1103: // PURPOSE
 1104: //   This is an interface routine meant to isolate the OS dependent
 1105: //   parts of the code, and to provide a debugging interface.  Each
 1106: //   different port and OS needs to provide it's own interface.  This
 1107: //   is the linux interface to the Areca "arcmsr" driver.  It allows ATA
 1108: //   commands to be passed through the SCSI driver.
 1109: // DETAILED DESCRIPTION OF ARGUMENTS
 1110: //   fd: is the file descriptor provided by open()
 1111: //   disknum is the disk number (0 to 15) in the RAID array
 1112: //   command: defines the different operations.
 1113: //   select: additional input data if needed (which log, which type of
 1114: //           self-test).
 1115: //   data:   location to write output data, if needed (512 bytes).
 1116: //   Note: not all commands use all arguments.
 1117: // RETURN VALUES
 1118: //  -1 if the command failed
 1119: //   0 if the command succeeded,
 1120: //   STATUS_CHECK routine: 
 1121: //  -1 if the command failed
 1122: //   0 if the command succeeded and disk SMART status is "OK"
 1123: //   1 if the command succeeded and disk SMART status is "FAILING"
 1124: 
 1125: 
 1126: /*FunctionCode*/
 1127: #define FUNCTION_READ_RQBUFFER               	0x0801
 1128: #define FUNCTION_WRITE_WQBUFFER              	0x0802
 1129: #define FUNCTION_CLEAR_RQBUFFER              	0x0803
 1130: #define FUNCTION_CLEAR_WQBUFFER              	0x0804
 1131: 
 1132: /* ARECA IO CONTROL CODE*/
 1133: #define ARCMSR_IOCTL_READ_RQBUFFER           _IOWR('F', FUNCTION_READ_RQBUFFER, sSRB_BUFFER)
 1134: #define ARCMSR_IOCTL_WRITE_WQBUFFER          _IOWR('F', FUNCTION_WRITE_WQBUFFER, sSRB_BUFFER)
 1135: #define ARCMSR_IOCTL_CLEAR_RQBUFFER          _IOWR('F', FUNCTION_CLEAR_RQBUFFER, sSRB_BUFFER)
 1136: #define ARCMSR_IOCTL_CLEAR_WQBUFFER          _IOWR('F', FUNCTION_CLEAR_WQBUFFER, sSRB_BUFFER)
 1137: #define ARECA_SIG_STR							"ARCMSR"
 1138: 
 1139: 
 1140: 
 1141: // The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver
 1142: typedef struct _SRB_IO_CONTROL
 1143: {
 1144: 	unsigned int HeaderLength;
 1145: 	unsigned char Signature[8];
 1146: 	unsigned int Timeout;
 1147: 	unsigned int ControlCode;
 1148: 	unsigned int ReturnCode;
 1149: 	unsigned int Length;
 1150: } sSRB_IO_CONTROL;
 1151: 
 1152: typedef struct _SRB_BUFFER
 1153: {
 1154: 	sSRB_IO_CONTROL srbioctl;
 1155: 	unsigned char   ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware
 1156: } sSRB_BUFFER;
 1157: 
 1158: 
 1159: // For debugging areca code
 1160: 
 1161: static void areca_dumpdata(unsigned char *block, int len)
 1162: {
 1163: 	int ln = (len / 16) + 1;	 // total line#
 1164: 	unsigned char c;
 1165: 	int pos = 0;
 1166: 
 1167: 	printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
 1168: 	printf("      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      ASCII      \n");
 1169: 	printf("=====================================================================\n");
 1170: 
 1171: 	for ( int l = 0; l < ln && len; l++ )
 1172: 	{
 1173: 		// printf the line# and the HEX data
 1174: 		// if a line data length < 16 then append the space to the tail of line to reach 16 chars
 1175: 		printf("%02X | ", l);
 1176: 		for ( pos = 0; pos < 16 && len; pos++, len-- )
 1177: 		{
 1178: 			c = block[l*16+pos];    
 1179: 			printf("%02X ", c);
 1180: 		}
 1181: 
 1182: 		if ( pos < 16 )
 1183: 		{
 1184: 			for ( int loop = pos; loop < 16; loop++ )
 1185: 			{
 1186: 				printf("   ");
 1187: 			}
 1188: 		}
 1189: 
 1190: 		// print ASCII char
 1191: 		for ( int loop = 0; loop < pos; loop++ )
 1192: 		{
 1193: 			c = block[l*16+loop];
 1194: 			if ( c >= 0x20 && c <= 0x7F )
 1195: 			{
 1196: 				printf("%c", c);
 1197: 			}
 1198: 			else
 1199: 			{
 1200: 				printf(".");
 1201: 			}
 1202: 		}
 1203: 		printf("\n");
 1204: 	}   
 1205: 	printf("=====================================================================\n");
 1206: }
 1207: 
 1208: 
 1209: static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len, void *ext_data /* reserved for further use */)
 1210: {
 1211: 	ARGUSED(ext_data);
 1212: 
 1213: 	int ioctlreturn = 0;
 1214: 	sSRB_BUFFER sBuf;
 1215: 
 1216: 	unsigned char *areca_return_packet;
 1217: 	int total = 0;
 1218: 	int expected = -1;
 1219: 	unsigned char return_buff[2048];
 1220: 	unsigned char *ptr = &return_buff[0];
 1221: 	memset(return_buff, 0, sizeof(return_buff));
 1222: 
 1223: 	memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
 1224: 
 1225: 
 1226: 	sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL);   
 1227: 	memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
 1228: 	sBuf.srbioctl.Timeout = 10000;      
 1229: 	sBuf.srbioctl.ControlCode = ARCMSR_IOCTL_READ_RQBUFFER;
 1230: 
 1231: 	switch ( arcmsr_cmd )
 1232: 	{
 1233: 	// command for writing data to driver
 1234: 	case ARCMSR_IOCTL_WRITE_WQBUFFER:   
 1235: 		if ( data && data_len )
 1236: 		{
 1237: 			sBuf.srbioctl.Length = data_len;    
 1238: 			memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
 1239: 		}
 1240: 		// commands for clearing related buffer of driver
 1241: 	case ARCMSR_IOCTL_CLEAR_RQBUFFER:
 1242: 	case ARCMSR_IOCTL_CLEAR_WQBUFFER:
 1243: 		break;
 1244: 		// command for reading data from driver
 1245: 	case ARCMSR_IOCTL_READ_RQBUFFER:    
 1246: 		break;
 1247: 	default:
 1248: 		// unknown arcmsr commands
 1249: 		return -1;
 1250: 	}
 1251: 
 1252: 
 1253: 	while ( 1 )
 1254: 	{
 1255: 		ioctlreturn = ioctl(fd,arcmsr_cmd,&sBuf);
 1256: 		if ( ioctlreturn  )
 1257: 		{
 1258: 			// errors found
 1259: 			break;
 1260: 		}
 1261: 
 1262: 		if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER )
 1263: 		{
 1264: 			// if succeeded, just returns the length of outgoing data
 1265: 			return data_len;
 1266: 		}
 1267: 
 1268: 		if ( sBuf.srbioctl.Length )
 1269: 		{
 1270: 			if(ata_debugmode)
 1271: 			    areca_dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
 1272: 			memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
 1273: 			ptr += sBuf.srbioctl.Length;
 1274: 			total += sBuf.srbioctl.Length;
 1275: 			// the returned bytes enough to compute payload length ?
 1276: 			if ( expected < 0 && total >= 5 )
 1277: 			{
 1278: 				areca_return_packet = (unsigned char *)&return_buff[0];
 1279: 				if ( areca_return_packet[0] == 0x5E && 
 1280: 					 areca_return_packet[1] == 0x01 && 
 1281: 					 areca_return_packet[2] == 0x61 )
 1282: 				{
 1283: 					// valid header, let's compute the returned payload length,
 1284: 					// we expected the total length is 
 1285: 					// payload + 3 bytes header + 2 bytes length + 1 byte checksum
 1286: 					expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
 1287: 				}
 1288: 			}
 1289: 
 1290: 			if ( total >= 7 && total >= expected )
 1291: 			{
 1292: 				//printf("total bytes received = %d, expected length = %d\n", total, expected);
 1293: 
 1294: 				// ------ Okay! we received enough --------
 1295: 				break;
 1296: 			}
 1297: 		}
 1298: 	}
 1299: 
 1300: 	// Deal with the different error cases
 1301: 	if ( ioctlreturn )
 1302: 	{
 1303: 		pout("ioctl write buffer failed code = %x\n", ioctlreturn);
 1304: 		return -2;
 1305: 	}
 1306: 
 1307: 
 1308: 	if ( data )
 1309: 	{
 1310: 		memcpy(data, return_buff, total);
 1311: 	}
 1312: 
 1313: 	return total;
 1314: }
 1315: 
 1316: 
 1317: freebsd_areca_device::freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
 1318: : smart_device(intf, dev_name, "areca", "areca"),
 1319:   freebsd_smart_device("ATA"),
 1320:   m_disknum(disknum),
 1321:   m_encnum(encnum)
 1322: {
 1323:   set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
 1324: }
 1325: 
 1326: // Areca RAID Controller
 1327: // int freebsd_areca_device::ata_command_interface(smart_command_set command, int select, char * data)
 1328: bool freebsd_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 
 1329: {
 1330: if (!ata_cmd_is_ok(in, 
 1331:     true, // data_out_support 
 1332:     false, // TODO: multi_sector_support 
 1333:     true) // ata_48bit_support 
 1334:     )
 1335:     return false; 
 1336: 
 1337: 	// ATA input registers
 1338: 	typedef struct _ATA_INPUT_REGISTERS
 1339: 	{
 1340: 		unsigned char features;
 1341: 		unsigned char sector_count;
 1342: 		unsigned char sector_number;
 1343: 		unsigned char cylinder_low; 
 1344: 		unsigned char cylinder_high;    
 1345: 		unsigned char device_head;  
 1346: 		unsigned char command;      
 1347: 		unsigned char reserved[8];
 1348: 		unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
 1349: 	} sATA_INPUT_REGISTERS;
 1350: 
 1351: 	// ATA output registers
 1352: 	// Note: The output registers is re-sorted for areca internal use only
 1353: 	typedef struct _ATA_OUTPUT_REGISTERS
 1354: 	{
 1355: 		unsigned char error;
 1356: 		unsigned char status;
 1357: 		unsigned char sector_count;
 1358: 		unsigned char sector_number;
 1359: 		unsigned char cylinder_low; 
 1360: 		unsigned char cylinder_high;
 1361: 	}sATA_OUTPUT_REGISTERS;
 1362: 
 1363: 	// Areca packet format for outgoing:
 1364: 	// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
 1365: 	// B[3~4] : 2 bytes command length + variant data length, little endian
 1366: 	// B[5]   : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
 1367: 	// B[6~last-1] : variant bytes payload data
 1368: 	// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
 1369: 	// 
 1370: 	// 
 1371: 	//   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte 
 1372: 	// +--------------------------------------------------------------------------------+
 1373: 	// + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
 1374: 	// +--------------------------------------------------------------------------------+
 1375: 	// 
 1376: 
 1377: 	//Areca packet format for incoming:
 1378: 	// B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
 1379: 	// B[3~4] : 2 bytes payload length, little endian
 1380: 	// B[5~last-1] : variant bytes returned payload data
 1381: 	// B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
 1382: 	// 
 1383: 	// 
 1384: 	//   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte 
 1385: 	// +-------------------------------------------------------------------+
 1386: 	// + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
 1387: 	// +-------------------------------------------------------------------+
 1388: 	unsigned char    areca_packet[640];
 1389: 	int areca_packet_len = sizeof(areca_packet);
 1390: 	unsigned char cs = 0;	
 1391: 
 1392: 	sATA_INPUT_REGISTERS *ata_cmd;
 1393: 
 1394: 	// For debugging
 1395: 	memset(areca_packet, 0, areca_packet_len);
 1396: 
 1397: 	// ----- BEGIN TO SETUP HEADERS -------
 1398: 	areca_packet[0] = 0x5E;
 1399: 	areca_packet[1] = 0x01;
 1400: 	areca_packet[2] = 0x61;
 1401: 	areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
 1402: 	areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
 1403: 	areca_packet[5] = 0x1c;	// areca defined code for ATA passthrough command
 1404: 
 1405: 	// ----- BEGIN TO SETUP PAYLOAD DATA -----
 1406: 	memcpy(&areca_packet[7], "SmrT", 4);	// areca defined password
 1407: 	ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
 1408: 
 1409: 	// Set registers
 1410:         {
 1411: 	    const ata_in_regs_48bit & r = in.in_regs;
 1412: 	    ata_cmd->features     = r.features_16;
 1413: 	    ata_cmd->sector_count  = r.sector_count_16;
 1414: 	    ata_cmd->sector_number = r.lba_low_16;
 1415: 	    ata_cmd->cylinder_low  = r.lba_mid_16;
 1416: 	    ata_cmd->cylinder_high = r.lba_high_16;
 1417: 	    ata_cmd->device_head   = r.device;
 1418: 	    ata_cmd->command      = r.command;
 1419: 	}
 1420: 	bool readdata = false; 
 1421: 	if (in.direction == ata_cmd_in::data_in) { 
 1422: 	    readdata = true;
 1423: 	    // the command will read data
 1424: 	    areca_packet[6] = 0x13;
 1425: 	}
 1426: 	else if ( in.direction == ata_cmd_in::no_data )
 1427: 	{
 1428: 		// the commands will return no data
 1429: 		areca_packet[6] = 0x15;
 1430: 	}
 1431: 	else if (in.direction == ata_cmd_in::data_out) 
 1432: 	{
 1433: 		// the commands will write data
 1434: 		memcpy(ata_cmd->data, in.buffer, in.size);
 1435: 		areca_packet[6] = 0x14;
 1436: 	}
 1437: 	else {
 1438: 	    // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
 1439: 	    return set_err(ENOTSUP, "DATA OUT not supported for this Areca controller type");
 1440: 	}
 1441: 
 1442: 	areca_packet[11] = m_disknum - 1;		// disk #
 1443: 	areca_packet[19] = m_encnum - 1;		// enc#
 1444: 
 1445: 	// ----- BEGIN TO SETUP CHECKSUM -----
 1446: 	for ( int loop = 3; loop < areca_packet_len - 1; loop++ )
 1447: 	{
 1448: 		cs += areca_packet[loop]; 
 1449: 	}
 1450: 	areca_packet[areca_packet_len-1] = cs;
 1451: 
 1452: 	// ----- BEGIN TO SEND TO ARECA DRIVER ------
 1453: 	int expected = 0;	
 1454: 	unsigned char return_buff[2048];
 1455: 	memset(return_buff, 0, sizeof(return_buff));
 1456: 
 1457: 	expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0, NULL);
 1458:         if (expected==-3) {
 1459: 	    return set_err(EIO);
 1460: 	}
 1461: 
 1462: 	expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0, NULL);
 1463: 	expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len, NULL);
 1464: 	if ( expected > 0 )
 1465: 	{
 1466: 		expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff), NULL);
 1467: 	}
 1468: 	if ( expected < 0 )
 1469: 	{
 1470: 		return -1;
 1471: 	}
 1472: 
 1473: 	// ----- VERIFY THE CHECKSUM -----
 1474: 	cs = 0;
 1475: 	for ( int loop = 3; loop < expected - 1; loop++ )
 1476: 	{
 1477: 		cs += return_buff[loop]; 
 1478: 	}
 1479: 
 1480: 	if ( return_buff[expected - 1] != cs )
 1481: 	{
 1482: 		return set_err(EIO);
 1483: 	}
 1484: 
 1485: 	sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ;
 1486: 	if ( ata_out->status )
 1487: 	{
 1488: 		if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
 1489: 		 && !nonempty((unsigned char *)in.buffer, in.size)) 
 1490: 		 {
 1491: 		    return set_err(ENODEV, "No drive on port %d", m_disknum);
 1492: 		 } 
 1493: 	}
 1494: 
 1495: 	// returns with data
 1496: 	if (readdata)
 1497: 	{
 1498: 		memcpy(in.buffer, &return_buff[7], in.size); 
 1499: 	}
 1500: 
 1501: 	// Return register values
 1502: 	{
 1503: 	    ata_out_regs_48bit & r = out.out_regs;
 1504: 	    r.error           = ata_out->error;
 1505: 	    r.sector_count_16 = ata_out->sector_count;
 1506: 	    r.lba_low_16      = ata_out->sector_number;
 1507: 	    r.lba_mid_16      = ata_out->cylinder_low;
 1508: 	    r.lba_high_16     = ata_out->cylinder_high;
 1509: 	    r.status          = ata_out->status;
 1510: 	}
 1511: 	return true;
 1512: }
 1513: 
 1514: 
 1515: 
 1516: /////////////////////////////////////////////////////////////////////////////
 1517: /// Implement CCISS RAID support with old functions
 1518: 
 1519: class freebsd_cciss_device
 1520: : public /*implements*/ scsi_device,
 1521:   public /*extends*/ freebsd_smart_device
 1522: {
 1523: public:
 1524:   freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
 1525: 
 1526:   virtual bool scsi_pass_through(scsi_cmnd_io * iop);
 1527:   virtual bool open();
 1528: 
 1529: private:
 1530:   unsigned char m_disknum; ///< Disk number.
 1531: };
 1532: 
 1533: bool freebsd_cciss_device::open()
 1534: {
 1535:   const char *dev = get_dev_name();
 1536:   int fd;
 1537:   if ((fd = ::open(dev,O_RDWR))<0) {
 1538:     set_err(errno);
 1539:     return false;
 1540:   }
 1541:   set_fd(fd);
 1542:   return true;
 1543: }
 1544: 
 1545: freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
 1546:   const char * dev_name, unsigned char disknum)
 1547: : smart_device(intf, dev_name, "cciss", "cciss"),
 1548:   freebsd_smart_device("SCSI"),
 1549:   m_disknum(disknum)
 1550: {
 1551:   set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
 1552: }
 1553: 
 1554: bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
 1555: {
 1556:   int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
 1557:   if (status < 0)
 1558:       return set_err(-status);
 1559:   return true;
 1560:   // not reached
 1561:   return true;
 1562: }
 1563: 
 1564: 
 1565: /////////////////////////////////////////////////////////////////////////////
 1566: /// SCSI open with autodetection support
 1567: 
 1568: smart_device * freebsd_scsi_device::autodetect_open()
 1569: {
 1570:   // Open device
 1571:   if (!open())
 1572:     return this;
 1573: 
 1574:   // No Autodetection if device type was specified by user
 1575:   if (*get_req_type())
 1576:     return this;
 1577: 
 1578:   // The code below is based on smartd.cpp:SCSIFilterKnown()
 1579: 
 1580:   // Get INQUIRY
 1581:   unsigned char req_buff[64] = {0, };
 1582:   int req_len = 36;
 1583:   if (scsiStdInquiry(this, req_buff, req_len)) {
 1584:     // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
 1585:     // watch this spot ... other devices could lock up here
 1586:     req_len = 64;
 1587:     if (scsiStdInquiry(this, req_buff, req_len)) {
 1588:       // device doesn't like INQUIRY commands
 1589:       close();
 1590:       set_err(EIO, "INQUIRY failed");
 1591:       return this;
 1592:     }
 1593:   }
 1594: 
 1595:   int avail_len = req_buff[4] + 5;
 1596:   int len = (avail_len < req_len ? avail_len : req_len);
 1597:   if (len < 36)
 1598:     return this;
 1599: 
 1600:   // Use INQUIRY to detect type
 1601: 
 1602:   // 3ware ?
 1603:   if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
 1604:     close();
 1605:     set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
 1606:                     "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
 1607:     return this;
 1608:   }
 1609: 
 1610:   // SAT or USB, skip MFI controllers because of bugs
 1611:   {
 1612:     smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
 1613:     if (newdev) {
 1614:       // NOTE: 'this' is now owned by '*newdev'
 1615:       if(!strcmp("mfi",m_camdev->sim_name)) {
 1616:         newdev->close();
 1617:         newdev->set_err(ENOSYS, "SATA device detected,\n"
 1618:           "MegaRAID SAT layer is reportedly buggy, use '-d sat' to try anyhow");
 1619:       }
 1620:       return newdev;
 1621:     }
 1622:   }
 1623: 
 1624:   // Nothing special found
 1625:   return this;
 1626: }
 1627: 
 1628: 
 1629: /////////////////////////////////////////////////////////////////////////////
 1630: /// Implement platform interface with old functions.
 1631: 
 1632: class freebsd_smart_interface
 1633: : public /*implements*/ smart_interface
 1634: {
 1635: public:
 1636:   virtual std::string get_os_version_str();
 1637: 
 1638:   virtual std::string get_app_examples(const char * appname);
 1639: 
 1640:   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
 1641:     const char * pattern = 0);
 1642: 
 1643: protected:
 1644:   virtual ata_device * get_ata_device(const char * name, const char * type);
 1645: 
 1646: #if FREEBSDVER > 800100
 1647:   virtual ata_device * get_atacam_device(const char * name, const char * type);
 1648: #endif
 1649: 
 1650:   virtual scsi_device * get_scsi_device(const char * name, const char * type);
 1651: 
 1652:   virtual smart_device * autodetect_smart_device(const char * name);
 1653: 
 1654:   virtual smart_device * get_custom_smart_device(const char * name, const char * type);
 1655: 
 1656:   virtual std::string get_valid_custom_dev_types_str();
 1657: };
 1658: 
 1659: 
 1660: //////////////////////////////////////////////////////////////////////
 1661: 
 1662: std::string freebsd_smart_interface::get_os_version_str()
 1663: {
 1664:   struct utsname osname;
 1665:   uname(&osname);
 1666:   return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
 1667: }
 1668: 
 1669: std::string freebsd_smart_interface::get_app_examples(const char * appname)
 1670: {
 1671:   if (!strcmp(appname, "smartctl"))
 1672:     return smartctl_examples;
 1673:   return "";
 1674: }
 1675: 
 1676: ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
 1677: {
 1678:   return new freebsd_ata_device(this, name, type);
 1679: }
 1680: 
 1681: #if FREEBSDVER > 800100
 1682: ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type)
 1683: {
 1684:   return new freebsd_atacam_device(this, name, type);
 1685: }
 1686: #endif
 1687: 
 1688: scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
 1689: {
 1690:   return new freebsd_scsi_device(this, name, type);
 1691: }
 1692: 
 1693: // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
 1694: // devices on system despite of it's names
 1695: //
 1696: // If any errors occur, leave errno set as it was returned by the
 1697: // system call, and return <0.
 1698: //
 1699: // arguments: 
 1700: // names: resulting array
 1701: // show_all - export duplicate device name or not
 1702: //
 1703: // Return values:
 1704: // -1:   error
 1705: // >=0: number of discovered devices
 1706: 
 1707: bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
 1708: {
 1709:   int fd;
 1710:   if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
 1711:     if (errno == ENOENT) /* There are no CAM device on this computer */
 1712:       return 0;
 1713:     int serrno = errno;
 1714:     pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
 1715:     errno = serrno;
 1716:     return false;
 1717:   }
 1718: 
 1719:   union ccb ccb;
 1720:   bzero(&ccb, sizeof(union ccb));
 1721: 
 1722:   ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
 1723:   ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
 1724:   ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
 1725: 
 1726:   ccb.ccb_h.func_code = XPT_DEV_MATCH;
 1727:   int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
 1728:   ccb.cdm.match_buf_len = bufsize;
 1729:   // TODO: Use local buffer instead of malloc() if possible
 1730:   ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
 1731:   bzero(ccb.cdm.matches,bufsize); // clear ccb.cdm.matches structure
 1732:   
 1733:   if (ccb.cdm.matches == NULL) {
 1734:     close(fd);
 1735:     throw std::bad_alloc();
 1736:   }
 1737:   ccb.cdm.num_matches = 0;
 1738:   ccb.cdm.num_patterns = 0;
 1739:   ccb.cdm.pattern_buf_len = 0;
 1740: 
 1741:   /*
 1742:    * We do the ioctl multiple times if necessary, in case there are
 1743:    * more than MAX_NUM_DEV nodes in the EDT.
 1744:    */
 1745:   int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool
 1746:   std::string devname;
 1747:   do {
 1748:     if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
 1749:       int serrno = errno;
 1750:       pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
 1751:       free(ccb.cdm.matches);
 1752:       close(fd);
 1753:       errno = serrno;
 1754:       return false;
 1755:     }
 1756: 
 1757:     if ((ccb.ccb_h.status != CAM_REQ_CMP)
 1758:       || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
 1759:       && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
 1760:       pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
 1761:       free(ccb.cdm.matches);
 1762:       close(fd);
 1763:       errno = ENXIO;
 1764:       return false;
 1765:     }
 1766: 
 1767:     for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
 1768:       struct bus_match_result *bus_result;
 1769:       struct device_match_result *dev_result;
 1770:       struct periph_match_result *periph_result;
 1771: 
 1772:       if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
 1773:         bus_result = &ccb.cdm.matches[i].result.bus_result;
 1774: 
 1775:         if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
 1776:         skip_bus = 1;
 1777:         else
 1778:           skip_bus = 0;
 1779:         changed = 1;
 1780:       } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
 1781:         dev_result = &ccb.cdm.matches[i].result.device_result;
 1782: 
 1783:         if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
 1784:           skip_device = 1;
 1785:         else
 1786:           skip_device = 0;
 1787:         
 1788:         //        /* Shall we skip non T_DIRECT devices ? */
 1789:         //        if (dev_result->inq_data.device != T_DIRECT)
 1790:         //          skip_device = 1;
 1791:         changed = 1;
 1792:       } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && 
 1793:           (skip_device == 0 || show_all)) { 
 1794:         /* One device may be populated as many peripherals (pass0 & da0 for example). 
 1795:         * We are searching for latest name
 1796:         */
 1797:         periph_result =  &ccb.cdm.matches[i].result.periph_result;
 1798:         devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
 1799:         changed = 0;
 1800:       };
 1801:       if ((changed == 1 || show_all) && !devname.empty()) {
 1802:         names.push_back(devname);
 1803:         devname.erase();
 1804:         changed = 0;
 1805:       };
 1806:     }
 1807: 
 1808:   } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
 1809: 
 1810:   if (!devname.empty())
 1811:     names.push_back(devname);
 1812: 
 1813:   free(ccb.cdm.matches);
 1814:   close(fd);
 1815:   return true;
 1816: }
 1817: 
 1818: // we are using ATA subsystem enumerator to found all ATA devices on system
 1819: // despite of it's names
 1820: //
 1821: // If any errors occur, leave errno set as it was returned by the
 1822: // system call, and return <0.
 1823: 
 1824: // Return values:
 1825: // -1:   error
 1826: // >=0: number of discovered devices
 1827: int get_dev_names_ata(char*** names) {
 1828:   struct ata_ioc_devices devices;
 1829:   int fd=-1,maxchannel,serrno=-1,n=0;
 1830:   char **mp = NULL;
 1831: 
 1832:   *names=NULL;
 1833: 
 1834:   if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
 1835:     if (errno == ENOENT) /* There are no ATA device on this computer */
 1836:       return 0;
 1837:     serrno = errno;
 1838:     pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
 1839:     n = -1;
 1840:     goto end;
 1841:   };
 1842: 
 1843:   if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
 1844:     serrno = errno;
 1845:     pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
 1846:     n = -1;
 1847:     goto end;
 1848:   };
 1849: 
 1850:   // allocate space for up to MAX_NUM_DEV number of ATA devices
 1851:   mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
 1852:   if (mp == NULL) {
 1853:     serrno=errno;
 1854:     pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
 1855:     n = -1;
 1856:     goto end;
 1857:   };
 1858: 
 1859:   for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
 1860:     int j;
 1861: 
 1862:     if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
 1863:       if (errno == ENXIO)
 1864:         continue; /* such channel not exist */
 1865:       pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
 1866:       n = -1;
 1867:       goto end;
 1868:     };
 1869:     for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
 1870:       if (devices.name[j][0] != '\0') {
 1871:         asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
 1872:         if (mp[n] == NULL) {
 1873:           pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
 1874:           n = -1;
 1875:           goto end;
 1876:         };
 1877:         bytes+=1+strlen(mp[n]);
 1878:         n++;
 1879:       };
 1880:     };
 1881:   };  
 1882:   mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
 1883:   if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL
 1884:     serrno=errno;
 1885:     pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
 1886:     n = -1;
 1887:     goto end;
 1888:   };
 1889:   bytes += (n)*(sizeof(char*)); // and set allocated byte count
 1890: 
 1891: end:
 1892:   if (fd>=0)
 1893:     close(fd);
 1894:   if (n <= 0) {
 1895:     free(mp);
 1896:     mp = NULL;
 1897:   }
 1898: 
 1899:   *names=mp;
 1900: 
 1901:   if (serrno>-1)
 1902:     errno=serrno;
 1903:   return n;
 1904: }
 1905: 
 1906: 
 1907: 
 1908: bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
 1909:   const char * type, const char * pattern /*= 0*/)
 1910: {
 1911:   if (pattern) {
 1912:     set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
 1913:     return false;
 1914:   }
 1915: 
 1916:   // Make namelists
 1917:   char * * atanames = 0; int numata = 0;
 1918:   if (!type || !strcmp(type, "ata")) {
 1919:     numata = get_dev_names_ata(&atanames);
 1920:     if (numata < 0) {
 1921:       set_err(ENOMEM);
 1922:       return false;
 1923:     }
 1924:   }
 1925: 
 1926:   std::vector<std::string> scsinames;
 1927:   if (!type || !strcmp(type, "scsi")) { // do not export duplicated names
 1928:     if (!get_dev_names_cam(scsinames, false)) {
 1929:       set_err(errno);
 1930:       return false;
 1931:     }
 1932:   }
 1933: 
 1934:   // Add to devlist
 1935:   int i;
 1936:   if (type==NULL)
 1937:     type="";
 1938:   for (i = 0; i < numata; i++) {
 1939:     ata_device * atadev = get_ata_device(atanames[i], type);
 1940:     if (atadev)
 1941:       devlist.push_back(atadev);
 1942:     free(atanames[i]);
 1943:   }
 1944:   if(numata) free(atanames);
 1945: 
 1946:   for (i = 0; i < (int)scsinames.size(); i++) {
 1947:     if(!*type) { // try USB autodetection if no type specified
 1948:       smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str());
 1949:       if(smartdev)
 1950:         devlist.push_back(smartdev);
 1951:     }
 1952:     else {
 1953:       scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type);
 1954:       if (scsidev)
 1955:         devlist.push_back(scsidev);
 1956:     }
 1957:   }
 1958:   return true;
 1959: }
 1960: 
 1961: 
 1962: #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
 1963: static char done[USB_MAX_DEVICES];
 1964: 
 1965: static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
 1966:   unsigned short & product_id, unsigned short & version)
 1967: { 
 1968: 
 1969:   struct usb_device_info di;
 1970:   int e, p, i;
 1971:   char devname[256];
 1972: 
 1973:   snprintf(devname, sizeof(devname),"umass%d",busno);
 1974: 
 1975:   di.udi_addr = a;
 1976:   e = ioctl(f, USB_DEVICEINFO, &di);
 1977:   if (e) {
 1978:     if (errno != ENXIO)
 1979:       printf("addr %d: I/O error\n", a);
 1980:     return 0;
 1981:   }
 1982:   done[a] = 1;
 1983: 
 1984:   // list devices
 1985:   for (i = 0; i < USB_MAX_DEVNAMES; i++) {
 1986:     if (di.udi_devnames[i][0]) {
 1987:       if(strcmp(di.udi_devnames[i],devname)==0) {
 1988:         // device found!
 1989:         vendor_id = di.udi_vendorNo;
 1990:         product_id = di.udi_productNo;
 1991:         version = di.udi_releaseNo;
 1992:         return 1;
 1993:         // FIXME
 1994:       }
 1995:     }
 1996:   }
 1997:   if (!rec)
 1998:     return 0;
 1999:   for (p = 0; p < di.udi_nports; p++) {
 2000:     int s = di.udi_ports[p];
 2001:     if (s >= USB_MAX_DEVICES) {
 2002:       continue;
 2003:     }
 2004:     if (s == 0)
 2005:       printf("addr 0 should never happen!\n");
 2006:     else {
 2007:       if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
 2008:     }
 2009:   }
 2010:   return 0;
 2011: }
 2012: #endif
 2013: 
 2014: 
 2015: static int usbdevlist(int busno,unsigned short & vendor_id,
 2016:   unsigned short & product_id, unsigned short & version)
 2017: {
 2018: #if (FREEBSDVER >= 800000) // libusb2 interface
 2019:   struct libusb20_device *pdev = NULL;
 2020:   struct libusb20_backend *pbe;
 2021:   uint32_t matches = 0;
 2022:   char buf[128]; // do not change!
 2023:   char devname[128];
 2024:   uint8_t n;
 2025:   struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
 2026: 
 2027:   pbe = libusb20_be_alloc_default();
 2028: 
 2029:   while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
 2030:     matches++;
 2031: 
 2032:     if (libusb20_dev_open(pdev, 0)) {
 2033:       warnx("libusb20_dev_open: could not open device");
 2034:       return 0;
 2035:     }
 2036: 
 2037:     pdesc=libusb20_dev_get_device_desc(pdev);
 2038: 
 2039:     snprintf(devname, sizeof(devname),"umass%d:",busno);
 2040:     for (n = 0; n != 255; n++) {
 2041:       if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
 2042:         break;
 2043:       if (buf[0] == 0)
 2044:         continue;
 2045:       if(strncmp(buf,devname,strlen(devname))==0){
 2046:         // found!
 2047:         vendor_id = pdesc->idVendor;
 2048:         product_id = pdesc->idProduct;
 2049:         version = pdesc->bcdDevice;
 2050:         libusb20_dev_close(pdev);
 2051:         libusb20_be_free(pbe);
 2052:         return 1;
 2053:       }
 2054:     }
 2055: 
 2056:     libusb20_dev_close(pdev);
 2057:   }
 2058: 
 2059:   if (matches == 0) {
 2060:     printf("No device match or lack of permissions.\n");
 2061:   }
 2062: 
 2063:   libusb20_be_free(pbe);
 2064: 
 2065:   return false;
 2066: #else // freebsd < 8.0 USB stack, ioctl interface
 2067: 
 2068:   int  i, f, a, rc;
 2069:   char buf[50];
 2070:   int ncont;
 2071: 
 2072:   for (ncont = 0, i = 0; i < 10; i++) {
 2073:     snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
 2074:     f = open(buf, O_RDONLY);
 2075:     if (f >= 0) {
 2076:       memset(done, 0, sizeof done);
 2077:       for (a = 1; a < USB_MAX_DEVICES; a++) {
 2078:         if (!done[a]) {
 2079:           rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
 2080:           if(rc) return 1;
 2081:         }
 2082: 
 2083:       }
 2084:       close(f);
 2085:     } else {
 2086:       if (errno == ENOENT || errno == ENXIO)
 2087:         continue;
 2088:       warn("%s", buf);
 2089:     }
 2090:     ncont++;
 2091:   }
 2092:   return 0;
 2093: #endif
 2094: }
 2095: 
 2096: smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
 2097: {
 2098:   unsigned short vendor_id = 0, product_id = 0, version = 0;
 2099:   struct cam_device *cam_dev;
 2100:   union ccb ccb;
 2101:   int bus=-1;
 2102:   int i,c;
 2103:   int len;
 2104:   const char * test_name = name;
 2105: 
 2106:   // if dev_name null, or string length zero
 2107:   if (!name || !(len = strlen(name)))
 2108:     return 0;
 2109: 
 2110:   // Dereference symlinks
 2111:   struct stat st;
 2112:   std::string pathbuf;
 2113:   if (!lstat(name, &st) && S_ISLNK(st.st_mode)) {
 2114:     char * p = realpath(name, (char *)0);
 2115:     if (p) {
 2116:       pathbuf = p;
 2117:       free(p);
 2118:       test_name = pathbuf.c_str();
 2119:     }
 2120:   }
 2121: 
 2122:   // check ATA bus
 2123:   char * * atanames = 0; int numata = 0;
 2124:   numata = get_dev_names_ata(&atanames);
 2125:   if (numata > 0) {
 2126:     // check ATA/ATAPI devices
 2127:     for (i = 0; i < numata; i++) {
 2128:       if(!strcmp(atanames[i],test_name)) {
 2129:         for (c = i; c < numata; c++) free(atanames[c]);
 2130:         free(atanames);
 2131:         return new freebsd_ata_device(this, test_name, "");
 2132:       }
 2133:       else free(atanames[i]);
 2134:     }
 2135:     if(numata) free(atanames);
 2136:   }
 2137:   else {
 2138:     if (numata < 0)
 2139:       pout("Unable to get ATA device list\n");
 2140:   }
 2141: 
 2142:   // check CAM
 2143:   std::vector<std::string> scsinames;
 2144:   if (!get_dev_names_cam(scsinames, true))
 2145:     pout("Unable to get CAM device list\n");
 2146:   else if (!scsinames.empty()) {
 2147:     // check all devices on CAM bus
 2148:     for (i = 0; i < (int)scsinames.size(); i++) {
 2149:       if(strcmp(scsinames[i].c_str(), test_name)==0)
 2150:       { // our disk device is CAM
 2151:         if ((cam_dev = cam_open_device(test_name, O_RDWR)) == NULL) {
 2152:           // open failure
 2153:           set_err(errno);
 2154:           return 0;
 2155:         }
 2156:         // zero the payload
 2157:         bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE);
 2158:         ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device
 2159:         if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
 2160:           warn("Get Transfer Settings CCB failed\n"
 2161:             "%s", strerror(errno));
 2162:           cam_close_device(cam_dev);
 2163:           return 0;
 2164:         }
 2165:         // now check if we are working with USB device, see umass.c
 2166:         if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found
 2167:           usbdevlist(bus,vendor_id, product_id, version);
 2168:           int bus=ccb.cpi.unit_number; // unit_number will match umass number
 2169:           cam_close_device(cam_dev);
 2170:           if(usbdevlist(bus,vendor_id, product_id, version)){
 2171:             const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
 2172:             if (usbtype)
 2173:               return get_sat_device(usbtype, new freebsd_scsi_device(this, test_name, ""));
 2174:           }
 2175:           return 0;
 2176:         }
 2177: #if FREEBSDVER > 800100
 2178:         // check if we have ATA device connected to CAM (ada)
 2179:         if(ccb.cpi.protocol == PROTO_ATA){
 2180:           cam_close_device(cam_dev);
 2181:           return new freebsd_atacam_device(this, test_name, "");
 2182:         }
 2183: #endif
 2184:         // close cam device, we don`t need it anymore
 2185:         cam_close_device(cam_dev);
 2186:         // handle as usual scsi
 2187:         return new freebsd_scsi_device(this, test_name, "");      
 2188:       }
 2189:     }
 2190:   }
 2191:   // device is LSI raid supported by mfi driver
 2192:   if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid")))
 2193:     set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information");
 2194:   // device type unknown
 2195:   return 0;
 2196: }
 2197: 
 2198: 
 2199: smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
 2200: {
 2201:   // 3Ware ?
 2202:   static const char * fbsd_dev_twe_ctrl = "/dev/twe";
 2203:   static const char * fbsd_dev_twa_ctrl = "/dev/twa";
 2204:   int disknum = -1, n1 = -1, n2 = -1, contr = -1;
 2205: 
 2206:   if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
 2207:     if (n2 != (int)strlen(type)) {
 2208:       set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
 2209:       return 0;
 2210:     }
 2211:     if (!(0 <= disknum && disknum <= 127)) {
 2212:       set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
 2213:       return 0;
 2214:     }
 2215: 
 2216:     // guess 3ware device type based on device name
 2217:     if (!strncmp(fbsd_dev_twa_ctrl, name, strlen(fbsd_dev_twa_ctrl))){
 2218:       contr=CONTROLLER_3WARE_9000_CHAR;
 2219:     }
 2220:     if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){
 2221:       contr=CONTROLLER_3WARE_678K_CHAR;
 2222:     }
 2223: 
 2224:     if(contr == -1){
 2225:       set_err(EINVAL, "3ware controller type unknown, use %sX or %sX devices", 
 2226:         fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl);
 2227:       return 0;
 2228:     }
 2229:     return new freebsd_escalade_device(this, name, contr, disknum);
 2230:   } 
 2231: 
 2232:   // Highpoint ?
 2233:   int controller = -1, channel = -1; disknum = 1;
 2234:   n1 = n2 = -1; int n3 = -1;
 2235:   if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
 2236:     int len = strlen(type);
 2237:     if (!(n2 == len || n3 == len)) {
 2238:       set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
 2239:       return 0;
 2240:     }
 2241:     if (!(1 <= controller && controller <= 8)) {
 2242:       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
 2243:       return 0;
 2244:     }
 2245:     if (!(1 <= channel && channel <= 16)) {
 2246:       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
 2247:       return 0;
 2248:     }
 2249:     if (!(1 <= disknum && disknum <= 15)) {
 2250:       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
 2251:       return 0;
 2252:     }
 2253:     return new freebsd_highpoint_device(this, name, controller, channel, disknum);
 2254:   }
 2255: 
 2256:   // CCISS ?
 2257:   disknum = n1 = n2 = -1;
 2258:   if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
 2259:     if (n2 != (int)strlen(type)) {
 2260:       set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
 2261:       return 0;
 2262:     }
 2263:     if (!(0 <= disknum && disknum <= 127)) {
 2264:       set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
 2265:       return 0;
 2266:     }
 2267:     return get_sat_device("sat,auto", new freebsd_cciss_device(this, name, disknum));
 2268:   }
 2269: #if FREEBSDVER > 800100
 2270:   // adaX devices ?
 2271:   if(!strcmp(type,"atacam"))
 2272:     return new freebsd_atacam_device(this, name, "");
 2273: #endif
 2274:   // Areca?
 2275:   disknum = n1 = n2 = -1;
 2276:   int encnum = 1;
 2277:   if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
 2278:     if (!(1 <= disknum && disknum <= 128)) {
 2279:       set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
 2280:       return 0;
 2281:     }
 2282:     if (!(1 <= encnum && encnum <= 8)) {
 2283:       set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
 2284:       return 0;
 2285:     }
 2286:     return new freebsd_areca_device(this, name, disknum);
 2287:   }
 2288: 
 2289:   return 0;
 2290: }
 2291: 
 2292: std::string freebsd_smart_interface::get_valid_custom_dev_types_str()
 2293: {
 2294:   return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E"
 2295: #if FREEBSDVER > 800100
 2296:   ", atacam"
 2297: #endif
 2298:   ;
 2299: }
 2300: 
 2301: } // namespace
 2302: 
 2303: /////////////////////////////////////////////////////////////////////////////
 2304: /// Initialize platform interface and register with smi()
 2305: 
 2306: void smart_interface::init()
 2307: {
 2308:   static os_freebsd::freebsd_smart_interface the_interface;
 2309:   smart_interface::set(&the_interface);
 2310: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>