Annotation of embedaddon/smartmontools/os_freebsd.cpp, revision 1.1

1.1     ! misho       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 3423 2011-10-06 16:43:44Z samm2 $" \
        !            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,1 /dev/arcmsr0\n"
        !           198:          "                              (Prints all SMART information for first disk \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: /// Implement standard SCSI support with old functions
        !           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: 
        !          1017:   // clear out structure, except for header that was filled in for us
        !          1018:   bzero(&(&ccb->ccb_h)[1],
        !          1019:     sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
        !          1020: 
        !          1021:   cam_fill_csio(&ccb->csio,
        !          1022:     /*retrires*/ 1,
        !          1023:     /*cbfcnp*/ NULL,
        !          1024:     /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)),
        !          1025:     /* tagaction */ MSG_SIMPLE_Q_TAG,
        !          1026:     /* dataptr */ iop->dxferp,
        !          1027:     /* datalen */ iop->dxfer_len,
        !          1028:     /* senselen */ iop->max_sense_len,
        !          1029:     /* cdblen */ iop->cmnd_len,
        !          1030:     /* timout (converted to seconds) */ iop->timeout*1000);
        !          1031:   memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len);
        !          1032: 
        !          1033:   if (cam_send_ccb(m_camdev,ccb) < 0) {
        !          1034:     warn("error sending SCSI ccb");
        !          1035:     cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
        !          1036:     cam_freeccb(ccb);
        !          1037:     return -EIO;
        !          1038:   }
        !          1039: 
        !          1040:   if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) {
        !          1041:     cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
        !          1042:     cam_freeccb(ccb);
        !          1043:     return -EIO;
        !          1044:   }
        !          1045: 
        !          1046:   if (iop->sensep) {
        !          1047:     memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data));
        !          1048:     iop->resp_sense_len = sizeof(struct scsi_sense_data);
        !          1049:   }
        !          1050: 
        !          1051:   iop->scsi_status = ccb->csio.scsi_status;
        !          1052: 
        !          1053:   cam_freeccb(ccb);
        !          1054: 
        !          1055:   if (report > 0) {
        !          1056:     int trunc;
        !          1057: 
        !          1058:     pout("  status=0\n");
        !          1059:     trunc = (iop->dxfer_len > 256) ? 1 : 0;
        !          1060: 
        !          1061:     pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
        !          1062:       (trunc ? " [only first 256 bytes shown]" : ""));
        !          1063:     dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
        !          1064:   }
        !          1065: 
        !          1066:   return true;
        !          1067: }
        !          1068: 
        !          1069: 
        !          1070: /////////////////////////////////////////////////////////////////////////////
        !          1071: /// Areca RAID support
        !          1072: 
        !          1073: class freebsd_areca_device
        !          1074: : public /*implements*/ ata_device,
        !          1075:   public /*extends*/ freebsd_smart_device
        !          1076: {
        !          1077: public:
        !          1078:   freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum);
        !          1079: 
        !          1080: protected:
        !          1081:   virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 
        !          1082: 
        !          1083: private:
        !          1084:   int m_disknum; ///< Disk number.
        !          1085: };
        !          1086: 
        !          1087: 
        !          1088: // PURPOSE
        !          1089: //   This is an interface routine meant to isolate the OS dependent
        !          1090: //   parts of the code, and to provide a debugging interface.  Each
        !          1091: //   different port and OS needs to provide it's own interface.  This
        !          1092: //   is the linux interface to the Areca "arcmsr" driver.  It allows ATA
        !          1093: //   commands to be passed through the SCSI driver.
        !          1094: // DETAILED DESCRIPTION OF ARGUMENTS
        !          1095: //   fd: is the file descriptor provided by open()
        !          1096: //   disknum is the disk number (0 to 15) in the RAID array
        !          1097: //   command: defines the different operations.
        !          1098: //   select: additional input data if needed (which log, which type of
        !          1099: //           self-test).
        !          1100: //   data:   location to write output data, if needed (512 bytes).
        !          1101: //   Note: not all commands use all arguments.
        !          1102: // RETURN VALUES
        !          1103: //  -1 if the command failed
        !          1104: //   0 if the command succeeded,
        !          1105: //   STATUS_CHECK routine: 
        !          1106: //  -1 if the command failed
        !          1107: //   0 if the command succeeded and disk SMART status is "OK"
        !          1108: //   1 if the command succeeded and disk SMART status is "FAILING"
        !          1109: 
        !          1110: 
        !          1111: /*FunctionCode*/
        !          1112: #define FUNCTION_READ_RQBUFFER                 0x0801
        !          1113: #define FUNCTION_WRITE_WQBUFFER                0x0802
        !          1114: #define FUNCTION_CLEAR_RQBUFFER                0x0803
        !          1115: #define FUNCTION_CLEAR_WQBUFFER                0x0804
        !          1116: 
        !          1117: /* ARECA IO CONTROL CODE*/
        !          1118: #define ARCMSR_IOCTL_READ_RQBUFFER           _IOWR('F', FUNCTION_READ_RQBUFFER, sSRB_BUFFER)
        !          1119: #define ARCMSR_IOCTL_WRITE_WQBUFFER          _IOWR('F', FUNCTION_WRITE_WQBUFFER, sSRB_BUFFER)
        !          1120: #define ARCMSR_IOCTL_CLEAR_RQBUFFER          _IOWR('F', FUNCTION_CLEAR_RQBUFFER, sSRB_BUFFER)
        !          1121: #define ARCMSR_IOCTL_CLEAR_WQBUFFER          _IOWR('F', FUNCTION_CLEAR_WQBUFFER, sSRB_BUFFER)
        !          1122: #define ARECA_SIG_STR                                                  "ARCMSR"
        !          1123: 
        !          1124: 
        !          1125: 
        !          1126: // The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver
        !          1127: typedef struct _SRB_IO_CONTROL
        !          1128: {
        !          1129:        unsigned int HeaderLength;
        !          1130:        unsigned char Signature[8];
        !          1131:        unsigned int Timeout;
        !          1132:        unsigned int ControlCode;
        !          1133:        unsigned int ReturnCode;
        !          1134:        unsigned int Length;
        !          1135: } sSRB_IO_CONTROL;
        !          1136: 
        !          1137: typedef struct _SRB_BUFFER
        !          1138: {
        !          1139:        sSRB_IO_CONTROL srbioctl;
        !          1140:        unsigned char   ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware
        !          1141: } sSRB_BUFFER;
        !          1142: 
        !          1143: 
        !          1144: // For debugging areca code
        !          1145: 
        !          1146: static void areca_dumpdata(unsigned char *block, int len)
        !          1147: {
        !          1148:        int ln = (len / 16) + 1;         // total line#
        !          1149:        unsigned char c;
        !          1150:        int pos = 0;
        !          1151: 
        !          1152:        printf(" Address = %p, Length = (0x%x)%d\n", block, len, len);
        !          1153:        printf("      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F      ASCII      \n");
        !          1154:        printf("=====================================================================\n");
        !          1155: 
        !          1156:        for ( int l = 0; l < ln && len; l++ )
        !          1157:        {
        !          1158:                // printf the line# and the HEX data
        !          1159:                // if a line data length < 16 then append the space to the tail of line to reach 16 chars
        !          1160:                printf("%02X | ", l);
        !          1161:                for ( pos = 0; pos < 16 && len; pos++, len-- )
        !          1162:                {
        !          1163:                        c = block[l*16+pos];    
        !          1164:                        printf("%02X ", c);
        !          1165:                }
        !          1166: 
        !          1167:                if ( pos < 16 )
        !          1168:                {
        !          1169:                        for ( int loop = pos; loop < 16; loop++ )
        !          1170:                        {
        !          1171:                                printf("   ");
        !          1172:                        }
        !          1173:                }
        !          1174: 
        !          1175:                // print ASCII char
        !          1176:                for ( int loop = 0; loop < pos; loop++ )
        !          1177:                {
        !          1178:                        c = block[l*16+loop];
        !          1179:                        if ( c >= 0x20 && c <= 0x7F )
        !          1180:                        {
        !          1181:                                printf("%c", c);
        !          1182:                        }
        !          1183:                        else
        !          1184:                        {
        !          1185:                                printf(".");
        !          1186:                        }
        !          1187:                }
        !          1188:                printf("\n");
        !          1189:        }   
        !          1190:        printf("=====================================================================\n");
        !          1191: }
        !          1192: 
        !          1193: 
        !          1194: static int arcmsr_command_handler(int fd, unsigned long arcmsr_cmd, unsigned char *data, int data_len, void *ext_data /* reserved for further use */)
        !          1195: {
        !          1196:        ARGUSED(ext_data);
        !          1197: 
        !          1198:        int ioctlreturn = 0;
        !          1199:        sSRB_BUFFER sBuf;
        !          1200: 
        !          1201:        unsigned char *areca_return_packet;
        !          1202:        int total = 0;
        !          1203:        int expected = -1;
        !          1204:        unsigned char return_buff[2048];
        !          1205:        unsigned char *ptr = &return_buff[0];
        !          1206:        memset(return_buff, 0, sizeof(return_buff));
        !          1207: 
        !          1208:        memset((unsigned char *)&sBuf, 0, sizeof(sBuf));
        !          1209: 
        !          1210: 
        !          1211:        sBuf.srbioctl.HeaderLength = sizeof(sSRB_IO_CONTROL);   
        !          1212:        memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR));
        !          1213:        sBuf.srbioctl.Timeout = 10000;      
        !          1214:        sBuf.srbioctl.ControlCode = ARCMSR_IOCTL_READ_RQBUFFER;
        !          1215: 
        !          1216:        switch ( arcmsr_cmd )
        !          1217:        {
        !          1218:        // command for writing data to driver
        !          1219:        case ARCMSR_IOCTL_WRITE_WQBUFFER:   
        !          1220:                if ( data && data_len )
        !          1221:                {
        !          1222:                        sBuf.srbioctl.Length = data_len;    
        !          1223:                        memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len);
        !          1224:                }
        !          1225:                // commands for clearing related buffer of driver
        !          1226:        case ARCMSR_IOCTL_CLEAR_RQBUFFER:
        !          1227:        case ARCMSR_IOCTL_CLEAR_WQBUFFER:
        !          1228:                break;
        !          1229:                // command for reading data from driver
        !          1230:        case ARCMSR_IOCTL_READ_RQBUFFER:    
        !          1231:                break;
        !          1232:        default:
        !          1233:                // unknown arcmsr commands
        !          1234:                return -1;
        !          1235:        }
        !          1236: 
        !          1237: 
        !          1238:        while ( 1 )
        !          1239:        {
        !          1240:                ioctlreturn = ioctl(fd,arcmsr_cmd,&sBuf);
        !          1241:                if ( ioctlreturn  )
        !          1242:                {
        !          1243:                        // errors found
        !          1244:                        break;
        !          1245:                }
        !          1246: 
        !          1247:                if ( arcmsr_cmd != ARCMSR_IOCTL_READ_RQBUFFER )
        !          1248:                {
        !          1249:                        // if succeeded, just returns the length of outgoing data
        !          1250:                        return data_len;
        !          1251:                }
        !          1252: 
        !          1253:                if ( sBuf.srbioctl.Length )
        !          1254:                {
        !          1255:                        if(ata_debugmode)
        !          1256:                            areca_dumpdata(&sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
        !          1257:                        memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length);
        !          1258:                        ptr += sBuf.srbioctl.Length;
        !          1259:                        total += sBuf.srbioctl.Length;
        !          1260:                        // the returned bytes enough to compute payload length ?
        !          1261:                        if ( expected < 0 && total >= 5 )
        !          1262:                        {
        !          1263:                                areca_return_packet = (unsigned char *)&return_buff[0];
        !          1264:                                if ( areca_return_packet[0] == 0x5E && 
        !          1265:                                         areca_return_packet[1] == 0x01 && 
        !          1266:                                         areca_return_packet[2] == 0x61 )
        !          1267:                                {
        !          1268:                                        // valid header, let's compute the returned payload length,
        !          1269:                                        // we expected the total length is 
        !          1270:                                        // payload + 3 bytes header + 2 bytes length + 1 byte checksum
        !          1271:                                        expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6;
        !          1272:                                }
        !          1273:                        }
        !          1274: 
        !          1275:                        if ( total >= 7 && total >= expected )
        !          1276:                        {
        !          1277:                                //printf("total bytes received = %d, expected length = %d\n", total, expected);
        !          1278: 
        !          1279:                                // ------ Okay! we received enough --------
        !          1280:                                break;
        !          1281:                        }
        !          1282:                }
        !          1283:        }
        !          1284: 
        !          1285:        // Deal with the different error cases
        !          1286:        if ( ioctlreturn )
        !          1287:        {
        !          1288:                pout("ioctl write buffer failed code = %x\n", ioctlreturn);
        !          1289:                return -2;
        !          1290:        }
        !          1291: 
        !          1292: 
        !          1293:        if ( data )
        !          1294:        {
        !          1295:                memcpy(data, return_buff, total);
        !          1296:        }
        !          1297: 
        !          1298:        return total;
        !          1299: }
        !          1300: 
        !          1301: 
        !          1302: freebsd_areca_device::freebsd_areca_device(smart_interface * intf, const char * dev_name, int disknum)
        !          1303: : smart_device(intf, dev_name, "areca", "areca"),
        !          1304:   freebsd_smart_device("ATA"),
        !          1305:   m_disknum(disknum)
        !          1306: {
        !          1307:   set_info().info_name = strprintf("%s [areca_%02d]", dev_name, disknum);
        !          1308: }
        !          1309: 
        !          1310: // Areca RAID Controller
        !          1311: // int freebsd_areca_device::ata_command_interface(smart_command_set command, int select, char * data)
        !          1312: bool freebsd_areca_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 
        !          1313: {
        !          1314: if (!ata_cmd_is_ok(in, 
        !          1315:     true, // data_out_support 
        !          1316:     false, // TODO: multi_sector_support 
        !          1317:     true) // ata_48bit_support 
        !          1318:     )
        !          1319:     return false; 
        !          1320: 
        !          1321:        // ATA input registers
        !          1322:        typedef struct _ATA_INPUT_REGISTERS
        !          1323:        {
        !          1324:                unsigned char features;
        !          1325:                unsigned char sector_count;
        !          1326:                unsigned char sector_number;
        !          1327:                unsigned char cylinder_low; 
        !          1328:                unsigned char cylinder_high;    
        !          1329:                unsigned char device_head;  
        !          1330:                unsigned char command;      
        !          1331:                unsigned char reserved[8];
        !          1332:                unsigned char data[512]; // [in/out] buffer for outgoing/incoming data
        !          1333:        } sATA_INPUT_REGISTERS;
        !          1334: 
        !          1335:        // ATA output registers
        !          1336:        // Note: The output registers is re-sorted for areca internal use only
        !          1337:        typedef struct _ATA_OUTPUT_REGISTERS
        !          1338:        {
        !          1339:                unsigned char error;
        !          1340:                unsigned char status;
        !          1341:                unsigned char sector_count;
        !          1342:                unsigned char sector_number;
        !          1343:                unsigned char cylinder_low; 
        !          1344:                unsigned char cylinder_high;
        !          1345:        }sATA_OUTPUT_REGISTERS;
        !          1346: 
        !          1347:        // Areca packet format for outgoing:
        !          1348:        // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
        !          1349:        // B[3~4] : 2 bytes command length + variant data length, little endian
        !          1350:        // B[5]   : 1 bytes areca defined command code, ATA passthrough command code is 0x1c
        !          1351:        // B[6~last-1] : variant bytes payload data
        !          1352:        // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
        !          1353:        // 
        !          1354:        // 
        !          1355:        //   header 3 bytes  length 2 bytes   cmd 1 byte    payload data x bytes  cs 1 byte 
        !          1356:        // +--------------------------------------------------------------------------------+
        !          1357:        // + 0x5E 0x01 0x61 |   0x00 0x00   |     0x1c   | .................... |   0x00    |
        !          1358:        // +--------------------------------------------------------------------------------+
        !          1359:        // 
        !          1360: 
        !          1361:        //Areca packet format for incoming:
        !          1362:        // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61
        !          1363:        // B[3~4] : 2 bytes payload length, little endian
        !          1364:        // B[5~last-1] : variant bytes returned payload data
        !          1365:        // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1])
        !          1366:        // 
        !          1367:        // 
        !          1368:        //   header 3 bytes  length 2 bytes   payload data x bytes  cs 1 byte 
        !          1369:        // +-------------------------------------------------------------------+
        !          1370:        // + 0x5E 0x01 0x61 |   0x00 0x00   | .................... |   0x00    |
        !          1371:        // +-------------------------------------------------------------------+
        !          1372:        unsigned char    areca_packet[640];
        !          1373:        int areca_packet_len = sizeof(areca_packet);
        !          1374:        unsigned char cs = 0;   
        !          1375: 
        !          1376:        sATA_INPUT_REGISTERS *ata_cmd;
        !          1377: 
        !          1378:        // For debugging
        !          1379:        memset(areca_packet, 0, areca_packet_len);
        !          1380: 
        !          1381:        // ----- BEGIN TO SETUP HEADERS -------
        !          1382:        areca_packet[0] = 0x5E;
        !          1383:        areca_packet[1] = 0x01;
        !          1384:        areca_packet[2] = 0x61;
        !          1385:        areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff);
        !          1386:        areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff);
        !          1387:        areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command
        !          1388: 
        !          1389:        // ----- BEGIN TO SETUP PAYLOAD DATA -----
        !          1390:        memcpy(&areca_packet[7], "SmrT", 4);    // areca defined password
        !          1391:        ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12];
        !          1392: 
        !          1393:        // Set registers
        !          1394:         {
        !          1395:            const ata_in_regs_48bit & r = in.in_regs;
        !          1396:            ata_cmd->features     = r.features_16;
        !          1397:            ata_cmd->sector_count  = r.sector_count_16;
        !          1398:            ata_cmd->sector_number = r.lba_low_16;
        !          1399:            ata_cmd->cylinder_low  = r.lba_mid_16;
        !          1400:            ata_cmd->cylinder_high = r.lba_high_16;
        !          1401:            ata_cmd->device_head   = r.device;
        !          1402:            ata_cmd->command      = r.command;
        !          1403:        }
        !          1404:        bool readdata = false; 
        !          1405:        if (in.direction == ata_cmd_in::data_in) { 
        !          1406:            readdata = true;
        !          1407:            // the command will read data
        !          1408:            areca_packet[6] = 0x13;
        !          1409:        }
        !          1410:        else if ( in.direction == ata_cmd_in::no_data )
        !          1411:        {
        !          1412:                // the commands will return no data
        !          1413:                areca_packet[6] = 0x15;
        !          1414:        }
        !          1415:        else if (in.direction == ata_cmd_in::data_out) 
        !          1416:        {
        !          1417:                // the commands will write data
        !          1418:                memcpy(ata_cmd->data, in.buffer, in.size);
        !          1419:                areca_packet[6] = 0x14;
        !          1420:        }
        !          1421:        else {
        !          1422:            // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE
        !          1423:            return set_err(ENOTSUP, "DATA OUT not supported for this Areca controller type");
        !          1424:        }
        !          1425: 
        !          1426:        areca_packet[11] = m_disknum - 1;                  // drive number
        !          1427: 
        !          1428:        // ----- BEGIN TO SETUP CHECKSUM -----
        !          1429:        for ( int loop = 3; loop < areca_packet_len - 1; loop++ )
        !          1430:        {
        !          1431:                cs += areca_packet[loop]; 
        !          1432:        }
        !          1433:        areca_packet[areca_packet_len-1] = cs;
        !          1434: 
        !          1435:        // ----- BEGIN TO SEND TO ARECA DRIVER ------
        !          1436:        int expected = 0;       
        !          1437:        unsigned char return_buff[2048];
        !          1438:        memset(return_buff, 0, sizeof(return_buff));
        !          1439: 
        !          1440:        expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_RQBUFFER, NULL, 0, NULL);
        !          1441:         if (expected==-3) {
        !          1442:            return set_err(EIO);
        !          1443:        }
        !          1444: 
        !          1445:        expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_CLEAR_WQBUFFER, NULL, 0, NULL);
        !          1446:        expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_WRITE_WQBUFFER, areca_packet, areca_packet_len, NULL);
        !          1447:        if ( expected > 0 )
        !          1448:        {
        !          1449:                expected = arcmsr_command_handler(get_fd(), ARCMSR_IOCTL_READ_RQBUFFER, return_buff, sizeof(return_buff), NULL);
        !          1450:        }
        !          1451:        if ( expected < 0 )
        !          1452:        {
        !          1453:                return -1;
        !          1454:        }
        !          1455: 
        !          1456:        // ----- VERIFY THE CHECKSUM -----
        !          1457:        cs = 0;
        !          1458:        for ( int loop = 3; loop < expected - 1; loop++ )
        !          1459:        {
        !          1460:                cs += return_buff[loop]; 
        !          1461:        }
        !          1462: 
        !          1463:        if ( return_buff[expected - 1] != cs )
        !          1464:        {
        !          1465:                return set_err(EIO);
        !          1466:        }
        !          1467: 
        !          1468:        sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ;
        !          1469:        if ( ata_out->status )
        !          1470:        {
        !          1471:                if ( in.in_regs.command == ATA_IDENTIFY_DEVICE
        !          1472:                 && !nonempty((unsigned char *)in.buffer, in.size)) 
        !          1473:                 {
        !          1474:                    return set_err(ENODEV, "No drive on port %d", m_disknum);
        !          1475:                 } 
        !          1476:        }
        !          1477: 
        !          1478:        // returns with data
        !          1479:        if (readdata)
        !          1480:        {
        !          1481:                memcpy(in.buffer, &return_buff[7], in.size); 
        !          1482:        }
        !          1483: 
        !          1484:        // Return register values
        !          1485:        {
        !          1486:            ata_out_regs_48bit & r = out.out_regs;
        !          1487:            r.error           = ata_out->error;
        !          1488:            r.sector_count_16 = ata_out->sector_count;
        !          1489:            r.lba_low_16      = ata_out->sector_number;
        !          1490:            r.lba_mid_16      = ata_out->cylinder_low;
        !          1491:            r.lba_high_16     = ata_out->cylinder_high;
        !          1492:            r.status          = ata_out->status;
        !          1493:        }
        !          1494:        return true;
        !          1495: }
        !          1496: 
        !          1497: 
        !          1498: 
        !          1499: /////////////////////////////////////////////////////////////////////////////
        !          1500: /// Implement CCISS RAID support with old functions
        !          1501: 
        !          1502: class freebsd_cciss_device
        !          1503: : public /*implements*/ scsi_device,
        !          1504:   public /*extends*/ freebsd_smart_device
        !          1505: {
        !          1506: public:
        !          1507:   freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
        !          1508: 
        !          1509:   virtual bool scsi_pass_through(scsi_cmnd_io * iop);
        !          1510:   virtual bool open();
        !          1511: 
        !          1512: private:
        !          1513:   unsigned char m_disknum; ///< Disk number.
        !          1514: };
        !          1515: 
        !          1516: bool freebsd_cciss_device::open()
        !          1517: {
        !          1518:   const char *dev = get_dev_name();
        !          1519:   int fd;
        !          1520:   if ((fd = ::open(dev,O_RDWR))<0) {
        !          1521:     set_err(errno);
        !          1522:     return false;
        !          1523:   }
        !          1524:   set_fd(fd);
        !          1525:   return true;
        !          1526: }
        !          1527: 
        !          1528: freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
        !          1529:   const char * dev_name, unsigned char disknum)
        !          1530: : smart_device(intf, dev_name, "cciss", "cciss"),
        !          1531:   freebsd_smart_device("SCSI"),
        !          1532:   m_disknum(disknum)
        !          1533: {
        !          1534:   set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
        !          1535: }
        !          1536: 
        !          1537: bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
        !          1538: {
        !          1539:   int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
        !          1540:   if (status < 0)
        !          1541:       return set_err(-status);
        !          1542:   return true;
        !          1543:   // not reached
        !          1544:   return true;
        !          1545: }
        !          1546: 
        !          1547: 
        !          1548: /////////////////////////////////////////////////////////////////////////////
        !          1549: /// SCSI open with autodetection support
        !          1550: 
        !          1551: smart_device * freebsd_scsi_device::autodetect_open()
        !          1552: {
        !          1553:   // Open device
        !          1554:   if (!open())
        !          1555:     return this;
        !          1556: 
        !          1557:   // No Autodetection if device type was specified by user
        !          1558:   if (*get_req_type())
        !          1559:     return this;
        !          1560: 
        !          1561:   // The code below is based on smartd.cpp:SCSIFilterKnown()
        !          1562: 
        !          1563:   // Get INQUIRY
        !          1564:   unsigned char req_buff[64] = {0, };
        !          1565:   int req_len = 36;
        !          1566:   if (scsiStdInquiry(this, req_buff, req_len)) {
        !          1567:     // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
        !          1568:     // watch this spot ... other devices could lock up here
        !          1569:     req_len = 64;
        !          1570:     if (scsiStdInquiry(this, req_buff, req_len)) {
        !          1571:       // device doesn't like INQUIRY commands
        !          1572:       close();
        !          1573:       set_err(EIO, "INQUIRY failed");
        !          1574:       return this;
        !          1575:     }
        !          1576:   }
        !          1577: 
        !          1578:   int avail_len = req_buff[4] + 5;
        !          1579:   int len = (avail_len < req_len ? avail_len : req_len);
        !          1580:   if (len < 36)
        !          1581:     return this;
        !          1582: 
        !          1583:   // Use INQUIRY to detect type
        !          1584: 
        !          1585:   // 3ware ?
        !          1586:   if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
        !          1587:     close();
        !          1588:     set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
        !          1589:                     "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
        !          1590:     return this;
        !          1591:   }
        !          1592: 
        !          1593:   // SAT or USB ?
        !          1594:   {
        !          1595:     smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
        !          1596:     if (newdev)
        !          1597:       // NOTE: 'this' is now owned by '*newdev'
        !          1598:       return newdev;
        !          1599:   }
        !          1600: 
        !          1601:   // Nothing special found
        !          1602:   return this;
        !          1603: }
        !          1604: 
        !          1605: 
        !          1606: /////////////////////////////////////////////////////////////////////////////
        !          1607: /// Implement platform interface with old functions.
        !          1608: 
        !          1609: class freebsd_smart_interface
        !          1610: : public /*implements*/ smart_interface
        !          1611: {
        !          1612: public:
        !          1613:   virtual std::string get_os_version_str();
        !          1614: 
        !          1615:   virtual std::string get_app_examples(const char * appname);
        !          1616: 
        !          1617:   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
        !          1618:     const char * pattern = 0);
        !          1619: 
        !          1620: protected:
        !          1621:   virtual ata_device * get_ata_device(const char * name, const char * type);
        !          1622: 
        !          1623: #if FREEBSDVER > 800100
        !          1624:   virtual ata_device * get_atacam_device(const char * name, const char * type);
        !          1625: #endif
        !          1626: 
        !          1627:   virtual scsi_device * get_scsi_device(const char * name, const char * type);
        !          1628: 
        !          1629:   virtual smart_device * autodetect_smart_device(const char * name);
        !          1630: 
        !          1631:   virtual smart_device * get_custom_smart_device(const char * name, const char * type);
        !          1632: 
        !          1633:   virtual std::string get_valid_custom_dev_types_str();
        !          1634: };
        !          1635: 
        !          1636: 
        !          1637: //////////////////////////////////////////////////////////////////////
        !          1638: 
        !          1639: std::string freebsd_smart_interface::get_os_version_str()
        !          1640: {
        !          1641:   struct utsname osname;
        !          1642:   uname(&osname);
        !          1643:   return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
        !          1644: }
        !          1645: 
        !          1646: std::string freebsd_smart_interface::get_app_examples(const char * appname)
        !          1647: {
        !          1648:   if (!strcmp(appname, "smartctl"))
        !          1649:     return smartctl_examples;
        !          1650:   return "";
        !          1651: }
        !          1652: 
        !          1653: ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
        !          1654: {
        !          1655:   return new freebsd_ata_device(this, name, type);
        !          1656: }
        !          1657: 
        !          1658: #if FREEBSDVER > 800100
        !          1659: ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type)
        !          1660: {
        !          1661:   return new freebsd_atacam_device(this, name, type);
        !          1662: }
        !          1663: #endif
        !          1664: 
        !          1665: scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
        !          1666: {
        !          1667:   return new freebsd_scsi_device(this, name, type);
        !          1668: }
        !          1669: 
        !          1670: // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
        !          1671: // devices on system despite of it's names
        !          1672: //
        !          1673: // If any errors occur, leave errno set as it was returned by the
        !          1674: // system call, and return <0.
        !          1675: //
        !          1676: // arguments: 
        !          1677: // names: resulting array
        !          1678: // show_all - export duplicate device name or not
        !          1679: //
        !          1680: // Return values:
        !          1681: // -1:   error
        !          1682: // >=0: number of discovered devices
        !          1683: 
        !          1684: bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
        !          1685: {
        !          1686:   int fd;
        !          1687:   if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
        !          1688:     if (errno == ENOENT) /* There are no CAM device on this computer */
        !          1689:       return 0;
        !          1690:     int serrno = errno;
        !          1691:     pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
        !          1692:     errno = serrno;
        !          1693:     return false;
        !          1694:   }
        !          1695: 
        !          1696:   union ccb ccb;
        !          1697:   bzero(&ccb, sizeof(union ccb));
        !          1698: 
        !          1699:   ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
        !          1700:   ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
        !          1701:   ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
        !          1702: 
        !          1703:   ccb.ccb_h.func_code = XPT_DEV_MATCH;
        !          1704:   int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
        !          1705:   ccb.cdm.match_buf_len = bufsize;
        !          1706:   // TODO: Use local buffer instead of malloc() if possible
        !          1707:   ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
        !          1708:   bzero(ccb.cdm.matches,bufsize); // clear ccb.cdm.matches structure
        !          1709:   
        !          1710:   if (ccb.cdm.matches == NULL) {
        !          1711:     close(fd);
        !          1712:     throw std::bad_alloc();
        !          1713:   }
        !          1714:   ccb.cdm.num_matches = 0;
        !          1715:   ccb.cdm.num_patterns = 0;
        !          1716:   ccb.cdm.pattern_buf_len = 0;
        !          1717: 
        !          1718:   /*
        !          1719:    * We do the ioctl multiple times if necessary, in case there are
        !          1720:    * more than MAX_NUM_DEV nodes in the EDT.
        !          1721:    */
        !          1722:   int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool
        !          1723:   std::string devname;
        !          1724:   do {
        !          1725:     if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
        !          1726:       int serrno = errno;
        !          1727:       pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
        !          1728:       free(ccb.cdm.matches);
        !          1729:       close(fd);
        !          1730:       errno = serrno;
        !          1731:       return false;
        !          1732:     }
        !          1733: 
        !          1734:     if ((ccb.ccb_h.status != CAM_REQ_CMP)
        !          1735:       || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
        !          1736:       && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
        !          1737:       pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
        !          1738:       free(ccb.cdm.matches);
        !          1739:       close(fd);
        !          1740:       errno = ENXIO;
        !          1741:       return false;
        !          1742:     }
        !          1743: 
        !          1744:     for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
        !          1745:       struct bus_match_result *bus_result;
        !          1746:       struct device_match_result *dev_result;
        !          1747:       struct periph_match_result *periph_result;
        !          1748: 
        !          1749:       if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
        !          1750:         bus_result = &ccb.cdm.matches[i].result.bus_result;
        !          1751: 
        !          1752:         if (strcmp(bus_result->dev_name,"ata") == 0 /* ATAPICAM devices will be probed as ATA devices, skip'em there */
        !          1753:           || strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
        !          1754:         skip_bus = 1;
        !          1755:         else
        !          1756:           skip_bus = 0;
        !          1757:         changed = 1;
        !          1758:       } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
        !          1759:         dev_result = &ccb.cdm.matches[i].result.device_result;
        !          1760: 
        !          1761:         if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
        !          1762:           skip_device = 1;
        !          1763:         else
        !          1764:           skip_device = 0;
        !          1765:         
        !          1766:         //        /* Shall we skip non T_DIRECT devices ? */
        !          1767:         //        if (dev_result->inq_data.device != T_DIRECT)
        !          1768:         //          skip_device = 1;
        !          1769:         changed = 1;
        !          1770:       } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && 
        !          1771:           (skip_device == 0 || show_all)) { 
        !          1772:         /* One device may be populated as many peripherals (pass0 & da0 for example). 
        !          1773:         * We are searching for latest name
        !          1774:         */
        !          1775:         periph_result =  &ccb.cdm.matches[i].result.periph_result;
        !          1776:         devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
        !          1777:         changed = 0;
        !          1778:       };
        !          1779:       if ((changed == 1 || show_all) && !devname.empty()) {
        !          1780:         names.push_back(devname);
        !          1781:         devname.erase();
        !          1782:         changed = 0;
        !          1783:       };
        !          1784:     }
        !          1785: 
        !          1786:   } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
        !          1787: 
        !          1788:   if (!devname.empty())
        !          1789:     names.push_back(devname);
        !          1790: 
        !          1791:   free(ccb.cdm.matches);
        !          1792:   close(fd);
        !          1793:   return true;
        !          1794: }
        !          1795: 
        !          1796: // we are using ATA subsystem enumerator to found all ATA devices on system
        !          1797: // despite of it's names
        !          1798: //
        !          1799: // If any errors occur, leave errno set as it was returned by the
        !          1800: // system call, and return <0.
        !          1801: 
        !          1802: // Return values:
        !          1803: // -1:   error
        !          1804: // >=0: number of discovered devices
        !          1805: int get_dev_names_ata(char*** names) {
        !          1806:   struct ata_ioc_devices devices;
        !          1807:   int fd=-1,maxchannel,serrno=-1,n=0;
        !          1808:   char **mp = NULL;
        !          1809: 
        !          1810:   *names=NULL;
        !          1811: 
        !          1812:   if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
        !          1813:     if (errno == ENOENT) /* There are no ATA device on this computer */
        !          1814:       return 0;
        !          1815:     serrno = errno;
        !          1816:     pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
        !          1817:     n = -1;
        !          1818:     goto end;
        !          1819:   };
        !          1820: 
        !          1821:   if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
        !          1822:     serrno = errno;
        !          1823:     pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
        !          1824:     n = -1;
        !          1825:     goto end;
        !          1826:   };
        !          1827: 
        !          1828:   // allocate space for up to MAX_NUM_DEV number of ATA devices
        !          1829:   mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
        !          1830:   if (mp == NULL) {
        !          1831:     serrno=errno;
        !          1832:     pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
        !          1833:     n = -1;
        !          1834:     goto end;
        !          1835:   };
        !          1836: 
        !          1837:   for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
        !          1838:     int j;
        !          1839: 
        !          1840:     if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
        !          1841:       if (errno == ENXIO)
        !          1842:         continue; /* such channel not exist */
        !          1843:       pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
        !          1844:       n = -1;
        !          1845:       goto end;
        !          1846:     };
        !          1847:     for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
        !          1848:       if (devices.name[j][0] != '\0') {
        !          1849:         asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
        !          1850:         if (mp[n] == NULL) {
        !          1851:           pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
        !          1852:           n = -1;
        !          1853:           goto end;
        !          1854:         };
        !          1855:         bytes+=1+strlen(mp[n]);
        !          1856:         n++;
        !          1857:       };
        !          1858:     };
        !          1859:   };  
        !          1860:   mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
        !          1861:   if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL
        !          1862:     serrno=errno;
        !          1863:     pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
        !          1864:     n = -1;
        !          1865:     goto end;
        !          1866:   };
        !          1867:   bytes += (n)*(sizeof(char*)); // and set allocated byte count
        !          1868: 
        !          1869: end:
        !          1870:   if (fd>=0)
        !          1871:     close(fd);
        !          1872:   if (n <= 0) {
        !          1873:     free(mp);
        !          1874:     mp = NULL;
        !          1875:   }
        !          1876: 
        !          1877:   *names=mp;
        !          1878: 
        !          1879:   if (serrno>-1)
        !          1880:     errno=serrno;
        !          1881:   return n;
        !          1882: }
        !          1883: 
        !          1884: 
        !          1885: 
        !          1886: bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
        !          1887:   const char * type, const char * pattern /*= 0*/)
        !          1888: {
        !          1889:   if (pattern) {
        !          1890:     set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
        !          1891:     return false;
        !          1892:   }
        !          1893: 
        !          1894:   // Make namelists
        !          1895:   char * * atanames = 0; int numata = 0;
        !          1896:   if (!type || !strcmp(type, "ata")) {
        !          1897:     numata = get_dev_names_ata(&atanames);
        !          1898:     if (numata < 0) {
        !          1899:       set_err(ENOMEM);
        !          1900:       return false;
        !          1901:     }
        !          1902:   }
        !          1903: 
        !          1904:   std::vector<std::string> scsinames;
        !          1905:   if (!type || !strcmp(type, "scsi")) { // do not export duplicated names
        !          1906:     if (!get_dev_names_cam(scsinames, false)) {
        !          1907:       set_err(errno);
        !          1908:       return false;
        !          1909:     }
        !          1910:   }
        !          1911: 
        !          1912:   // Add to devlist
        !          1913:   int i;
        !          1914:   if (type==NULL)
        !          1915:     type="";
        !          1916:   for (i = 0; i < numata; i++) {
        !          1917:     ata_device * atadev = get_ata_device(atanames[i], type);
        !          1918:     if (atadev)
        !          1919:       devlist.push_back(atadev);
        !          1920:     free(atanames[i]);
        !          1921:   }
        !          1922:   if(numata) free(atanames);
        !          1923: 
        !          1924:   for (i = 0; i < (int)scsinames.size(); i++) {
        !          1925:     if(!*type) { // try USB autodetection if no type specified
        !          1926:       smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str());
        !          1927:       if(smartdev)
        !          1928:         devlist.push_back(smartdev);
        !          1929:     }
        !          1930:     else {
        !          1931:       scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type);
        !          1932:       if (scsidev)
        !          1933:         devlist.push_back(scsidev);
        !          1934:     }
        !          1935:   }
        !          1936:   return true;
        !          1937: }
        !          1938: 
        !          1939: 
        !          1940: #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
        !          1941: static char done[USB_MAX_DEVICES];
        !          1942: 
        !          1943: static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
        !          1944:   unsigned short & product_id, unsigned short & version)
        !          1945: { 
        !          1946: 
        !          1947:   struct usb_device_info di;
        !          1948:   int e, p, i;
        !          1949:   char devname[256];
        !          1950: 
        !          1951:   snprintf(devname, sizeof(devname),"umass%d",busno);
        !          1952: 
        !          1953:   di.udi_addr = a;
        !          1954:   e = ioctl(f, USB_DEVICEINFO, &di);
        !          1955:   if (e) {
        !          1956:     if (errno != ENXIO)
        !          1957:       printf("addr %d: I/O error\n", a);
        !          1958:     return 0;
        !          1959:   }
        !          1960:   done[a] = 1;
        !          1961: 
        !          1962:   // list devices
        !          1963:   for (i = 0; i < USB_MAX_DEVNAMES; i++) {
        !          1964:     if (di.udi_devnames[i][0]) {
        !          1965:       if(strcmp(di.udi_devnames[i],devname)==0) {
        !          1966:         // device found!
        !          1967:         vendor_id = di.udi_vendorNo;
        !          1968:         product_id = di.udi_productNo;
        !          1969:         version = di.udi_releaseNo;
        !          1970:         return 1;
        !          1971:         // FIXME
        !          1972:       }
        !          1973:     }
        !          1974:   }
        !          1975:   if (!rec)
        !          1976:     return 0;
        !          1977:   for (p = 0; p < di.udi_nports; p++) {
        !          1978:     int s = di.udi_ports[p];
        !          1979:     if (s >= USB_MAX_DEVICES) {
        !          1980:       continue;
        !          1981:     }
        !          1982:     if (s == 0)
        !          1983:       printf("addr 0 should never happen!\n");
        !          1984:     else {
        !          1985:       if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
        !          1986:     }
        !          1987:   }
        !          1988:   return 0;
        !          1989: }
        !          1990: #endif
        !          1991: 
        !          1992: 
        !          1993: static int usbdevlist(int busno,unsigned short & vendor_id,
        !          1994:   unsigned short & product_id, unsigned short & version)
        !          1995: {
        !          1996: #if (FREEBSDVER >= 800000) // libusb2 interface
        !          1997:   struct libusb20_device *pdev = NULL;
        !          1998:   struct libusb20_backend *pbe;
        !          1999:   uint32_t matches = 0;
        !          2000:   char buf[128]; // do not change!
        !          2001:   char devname[128];
        !          2002:   uint8_t n;
        !          2003:   struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
        !          2004: 
        !          2005:   pbe = libusb20_be_alloc_default();
        !          2006: 
        !          2007:   while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
        !          2008:     matches++;
        !          2009: 
        !          2010:     if (libusb20_dev_open(pdev, 0)) {
        !          2011:       warnx("libusb20_dev_open: could not open device");
        !          2012:       return 0;
        !          2013:     }
        !          2014: 
        !          2015:     pdesc=libusb20_dev_get_device_desc(pdev);
        !          2016: 
        !          2017:     snprintf(devname, sizeof(devname),"umass%d:",busno);
        !          2018:     for (n = 0; n != 255; n++) {
        !          2019:       if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
        !          2020:         break;
        !          2021:       if (buf[0] == 0)
        !          2022:         continue;
        !          2023:       if(strncmp(buf,devname,strlen(devname))==0){
        !          2024:         // found!
        !          2025:         vendor_id = pdesc->idVendor;
        !          2026:         product_id = pdesc->idProduct;
        !          2027:         version = pdesc->bcdDevice;
        !          2028:         libusb20_dev_close(pdev);
        !          2029:         libusb20_be_free(pbe);
        !          2030:         return 1;
        !          2031:       }
        !          2032:     }
        !          2033: 
        !          2034:     libusb20_dev_close(pdev);
        !          2035:   }
        !          2036: 
        !          2037:   if (matches == 0) {
        !          2038:     printf("No device match or lack of permissions.\n");
        !          2039:   }
        !          2040: 
        !          2041:   libusb20_be_free(pbe);
        !          2042: 
        !          2043:   return false;
        !          2044: #else // freebsd < 8.0 USB stack, ioctl interface
        !          2045: 
        !          2046:   int  i, f, a, rc;
        !          2047:   char buf[50];
        !          2048:   int ncont;
        !          2049: 
        !          2050:   for (ncont = 0, i = 0; i < 10; i++) {
        !          2051:     snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
        !          2052:     f = open(buf, O_RDONLY);
        !          2053:     if (f >= 0) {
        !          2054:       memset(done, 0, sizeof done);
        !          2055:       for (a = 1; a < USB_MAX_DEVICES; a++) {
        !          2056:         if (!done[a]) {
        !          2057:           rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
        !          2058:           if(rc) return 1;
        !          2059:         }
        !          2060: 
        !          2061:       }
        !          2062:       close(f);
        !          2063:     } else {
        !          2064:       if (errno == ENOENT || errno == ENXIO)
        !          2065:         continue;
        !          2066:       warn("%s", buf);
        !          2067:     }
        !          2068:     ncont++;
        !          2069:   }
        !          2070:   return 0;
        !          2071: #endif
        !          2072: }
        !          2073: 
        !          2074: smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
        !          2075: {
        !          2076:   unsigned short vendor_id = 0, product_id = 0, version = 0;
        !          2077:   struct cam_device *cam_dev;
        !          2078:   union ccb ccb;
        !          2079:   int bus=-1;
        !          2080:   int i,c;
        !          2081:   int len;
        !          2082: 
        !          2083:   // if dev_name null, or string length zero
        !          2084:   if (!name || !(len = strlen(name)))
        !          2085:     return 0;
        !          2086: 
        !          2087:   // check ATA bus
        !          2088:   char * * atanames = 0; int numata = 0;
        !          2089:   numata = get_dev_names_ata(&atanames);
        !          2090:   if (numata > 0) {
        !          2091:     // check ATA/ATAPI devices
        !          2092:     for (i = 0; i < numata; i++) {
        !          2093:       if(!strcmp(atanames[i],name)) {
        !          2094:         for (c = i; c < numata; c++) free(atanames[c]);
        !          2095:         free(atanames);
        !          2096:         return new freebsd_ata_device(this, name, "");
        !          2097:       }
        !          2098:       else free(atanames[i]);
        !          2099:     }
        !          2100:     if(numata) free(atanames);
        !          2101:   }
        !          2102:   else {
        !          2103:     if (numata < 0)
        !          2104:       pout("Unable to get ATA device list\n");
        !          2105:   }
        !          2106: 
        !          2107:   // check CAM
        !          2108:   std::vector<std::string> scsinames;
        !          2109:   if (!get_dev_names_cam(scsinames, true))
        !          2110:     pout("Unable to get CAM device list\n");
        !          2111:   else if (!scsinames.empty()) {
        !          2112:     // check all devices on CAM bus
        !          2113:     for (i = 0; i < (int)scsinames.size(); i++) {
        !          2114:       if(strcmp(scsinames[i].c_str(), name)==0)
        !          2115:       { // our disk device is CAM
        !          2116:         if ((cam_dev = cam_open_device(name, O_RDWR)) == NULL) {
        !          2117:           // open failure
        !          2118:           set_err(errno);
        !          2119:           return 0;
        !          2120:         }
        !          2121:         
        !          2122:         // zero the payload
        !          2123:         bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE);
        !          2124:         ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device
        !          2125:         if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
        !          2126:           warn("Get Transfer Settings CCB failed\n"
        !          2127:             "%s", strerror(errno));
        !          2128:           cam_close_device(cam_dev);
        !          2129:           return 0;
        !          2130:         }
        !          2131:         // now check if we are working with USB device, see umass.c
        !          2132:         if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found
        !          2133:           usbdevlist(bus,vendor_id, product_id, version);
        !          2134:           int bus=ccb.cpi.unit_number; // unit_number will match umass number
        !          2135:           cam_close_device(cam_dev);
        !          2136:           if(usbdevlist(bus,vendor_id, product_id, version)){
        !          2137:             const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
        !          2138:             if (usbtype)
        !          2139:               return get_sat_device(usbtype, new freebsd_scsi_device(this, name, ""));
        !          2140:           }
        !          2141:           return 0;
        !          2142:         }
        !          2143: #if FREEBSDVER > 800100
        !          2144:         // check if we have ATA device connected to CAM (ada)
        !          2145:         if(ccb.cpi.protocol == PROTO_ATA){
        !          2146:           cam_close_device(cam_dev);
        !          2147:           return new freebsd_atacam_device(this, name, "");
        !          2148:         }
        !          2149: #endif
        !          2150:         // close cam device, we don`t need it anymore
        !          2151:         cam_close_device(cam_dev);
        !          2152:         // handle as usual scsi
        !          2153:         return new freebsd_scsi_device(this, name, "");      
        !          2154:       }
        !          2155:     }
        !          2156:   }
        !          2157:   // device is LSI raid supported by mfi driver
        !          2158:   if(!strncmp("/dev/mfid", name, strlen("/dev/mfid")))
        !          2159:     set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information");
        !          2160:   // device type unknown
        !          2161:   return 0;
        !          2162: }
        !          2163: 
        !          2164: 
        !          2165: smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
        !          2166: {
        !          2167:   // 3Ware ?
        !          2168:   static const char * fbsd_dev_twe_ctrl = "/dev/twe";
        !          2169:   static const char * fbsd_dev_twa_ctrl = "/dev/twa";
        !          2170:   int disknum = -1, n1 = -1, n2 = -1, contr = -1;
        !          2171: 
        !          2172:   if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
        !          2173:     if (n2 != (int)strlen(type)) {
        !          2174:       set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
        !          2175:       return 0;
        !          2176:     }
        !          2177:     if (!(0 <= disknum && disknum <= 127)) {
        !          2178:       set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
        !          2179:       return 0;
        !          2180:     }
        !          2181: 
        !          2182:     // guess 3ware device type based on device name
        !          2183:     if (!strncmp(fbsd_dev_twa_ctrl, name, strlen(fbsd_dev_twa_ctrl))){
        !          2184:       contr=CONTROLLER_3WARE_9000_CHAR;
        !          2185:     }
        !          2186:     if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){
        !          2187:       contr=CONTROLLER_3WARE_678K_CHAR;
        !          2188:     }
        !          2189: 
        !          2190:     if(contr == -1){
        !          2191:       set_err(EINVAL, "3ware controller type unknown, use %sX or %sX devices", 
        !          2192:         fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl);
        !          2193:       return 0;
        !          2194:     }
        !          2195:     return new freebsd_escalade_device(this, name, contr, disknum);
        !          2196:   } 
        !          2197: 
        !          2198:   // Highpoint ?
        !          2199:   int controller = -1, channel = -1; disknum = 1;
        !          2200:   n1 = n2 = -1; int n3 = -1;
        !          2201:   if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
        !          2202:     int len = strlen(type);
        !          2203:     if (!(n2 == len || n3 == len)) {
        !          2204:       set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
        !          2205:       return 0;
        !          2206:     }
        !          2207:     if (!(1 <= controller && controller <= 8)) {
        !          2208:       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
        !          2209:       return 0;
        !          2210:     }
        !          2211:     if (!(1 <= channel && channel <= 16)) {
        !          2212:       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
        !          2213:       return 0;
        !          2214:     }
        !          2215:     if (!(1 <= disknum && disknum <= 15)) {
        !          2216:       set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
        !          2217:       return 0;
        !          2218:     }
        !          2219:     return new freebsd_highpoint_device(this, name, controller, channel, disknum);
        !          2220:   }
        !          2221: 
        !          2222:   // CCISS ?
        !          2223:   disknum = n1 = n2 = -1;
        !          2224:   if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
        !          2225:     if (n2 != (int)strlen(type)) {
        !          2226:       set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
        !          2227:       return 0;
        !          2228:     }
        !          2229:     if (!(0 <= disknum && disknum <= 127)) {
        !          2230:       set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
        !          2231:       return 0;
        !          2232:     }
        !          2233:     return new freebsd_cciss_device(this, name, disknum);
        !          2234:   }
        !          2235: #if FREEBSDVER > 800100
        !          2236:   // adaX devices ?
        !          2237:   if(!strcmp(type,"atacam"))
        !          2238:     return new freebsd_atacam_device(this, name, "");
        !          2239: #endif
        !          2240:   // Areca?
        !          2241:   disknum = n1 = n2 = -1;
        !          2242:   if (sscanf(type, "areca,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
        !          2243:     if (n2 != (int)strlen(type)) {
        !          2244:       set_err(EINVAL, "Option -d areca,N requires N to be a non-negative integer");
        !          2245:       return 0;
        !          2246:     }
        !          2247:     if (!(1 <= disknum && disknum <= 24)) {
        !          2248:       set_err(EINVAL, "Option -d areca,N (N=%d) must have 1 <= N <= 24", disknum);
        !          2249:       return 0;
        !          2250:     }
        !          2251:     return new freebsd_areca_device(this, name, disknum);
        !          2252:   }
        !          2253: 
        !          2254:   return 0;
        !          2255: }
        !          2256: 
        !          2257: std::string freebsd_smart_interface::get_valid_custom_dev_types_str()
        !          2258: {
        !          2259:   return "3ware,N, hpt,L/M/N, cciss,N, areca,N"
        !          2260: #if FREEBSDVER > 800100
        !          2261:   ", atacam"
        !          2262: #endif
        !          2263:   ;
        !          2264: }
        !          2265: 
        !          2266: } // namespace
        !          2267: 
        !          2268: /////////////////////////////////////////////////////////////////////////////
        !          2269: /// Initialize platform interface and register with smi()
        !          2270: 
        !          2271: void smart_interface::init()
        !          2272: {
        !          2273:   static os_freebsd::freebsd_smart_interface the_interface;
        !          2274:   smart_interface::set(&the_interface);
        !          2275: }

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