File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / os_freebsd.cpp
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:54:03 2013 UTC (10 years, 7 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_2, HEAD
v 6.2

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

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