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

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

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