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