|
smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
|
00001 /* 00002 * os_freebsd.c 00003 * 00004 * Home page of code is: http://smartmontools.sourceforge.net 00005 * 00006 * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net> 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2, or (at your option) 00011 * any later version. 00012 * 00013 * You should have received a copy of the GNU General Public License 00014 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. 00015 * 00016 */ 00017 00018 #include <stdio.h> 00019 #include <sys/types.h> 00020 #include <dirent.h> 00021 #include <fcntl.h> 00022 #include <err.h> 00023 #include <errno.h> 00024 #include <camlib.h> 00025 #include <cam/scsi/scsi_message.h> 00026 #include <cam/scsi/scsi_pass.h> 00027 #if defined(__DragonFly__) 00028 #include <sys/nata.h> 00029 #else 00030 #include <sys/ata.h> 00031 #endif 00032 #include <sys/stat.h> 00033 #include <unistd.h> 00034 #include <glob.h> 00035 #include <stddef.h> 00036 #include <paths.h> 00037 #include <sys/utsname.h> 00038 00039 #include "config.h" 00040 #include "int64.h" 00041 #include "atacmds.h" 00042 #include "scsicmds.h" 00043 #include "cciss.h" 00044 #include "utility.h" 00045 #include "os_freebsd.h" 00046 00047 #include "dev_interface.h" 00048 #include "dev_ata_cmd_set.h" 00049 #include "dev_areca.h" 00050 00051 #define USBDEV "/dev/usb" 00052 #if defined(__FreeBSD_version) 00053 00054 // This way we define one variable for the GNU/kFreeBSD and FreeBSD 00055 #define FREEBSDVER __FreeBSD_version 00056 #else 00057 #define FREEBSDVER __FreeBSD_kernel_version 00058 #endif 00059 00060 #if (FREEBSDVER >= 800000) 00061 #include <libusb20_desc.h> 00062 #include <libusb20.h> 00063 #elif defined(__DragonFly__) 00064 #include <bus/usb/usb.h> 00065 #include <bus/usb/usbhid.h> 00066 #else 00067 #include <dev/usb/usb.h> 00068 #include <dev/usb/usbhid.h> 00069 #endif 00070 00071 #define CONTROLLER_3WARE_9000_CHAR 0x01 00072 #define CONTROLLER_3WARE_678K_CHAR 0x02 00073 00074 #ifndef PATHINQ_SETTINGS_SIZE 00075 #define PATHINQ_SETTINGS_SIZE 128 00076 #endif 00077 00078 const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3771 2013-02-10 15:36:55Z samm2 $" \ 00079 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; 00080 00081 #define NO_RETURN 0 00082 #define BAD_SMART 1 00083 #define NO_DISK_3WARE 2 00084 #define BAD_KERNEL 3 00085 #define MAX_MSG 3 00086 00087 // Utility function for printing warnings 00088 void printwarning(int msgNo, const char* extra) { 00089 static int printed[] = {0,0,0,0}; 00090 static const char* message[]={ 00091 "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", 00092 00093 "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n", 00094 00095 "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n", 00096 00097 "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n" 00098 }; 00099 00100 if (msgNo >= 0 && msgNo <= MAX_MSG) { 00101 if (!printed[msgNo]) { 00102 printed[msgNo] = 1; 00103 pout("%s", message[msgNo]); 00104 if (extra) 00105 pout("%s",extra); 00106 } 00107 } 00108 return; 00109 } 00110 00111 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c 00112 00113 #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520 00114 #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048 00115 #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) ) 00116 00117 #ifndef ATA_DEVICE 00118 #define ATA_DEVICE "/dev/ata" 00119 #endif 00120 00121 #define ARGUSED(x) ((void)(x)) 00122 00123 // global variable holding byte count of allocated memory 00124 long long bytes; 00125 extern unsigned char failuretest_permissive; 00126 00127 ///////////////////////////////////////////////////////////////////////////// 00128 00129 namespace os_freebsd { // No need to publish anything, name provided for Doxygen 00130 00131 ///////////////////////////////////////////////////////////////////////////// 00132 /// Implement shared open/close routines with old functions. 00133 00134 class freebsd_smart_device 00135 : virtual public /*implements*/ smart_device 00136 { 00137 public: 00138 explicit freebsd_smart_device(const char * mode) 00139 : smart_device(never_called), 00140 m_fd(-1), m_mode(mode) { } 00141 00142 virtual ~freebsd_smart_device() throw(); 00143 00144 virtual bool is_open() const; 00145 00146 virtual bool open(); 00147 00148 virtual bool close(); 00149 00150 protected: 00151 /// Return filedesc for derived classes. 00152 int get_fd() const 00153 { return m_fd; } 00154 00155 void set_fd(int fd) 00156 { m_fd = fd; } 00157 00158 private: 00159 int m_fd; ///< filedesc, -1 if not open. 00160 const char * m_mode; ///< Mode string for deviceopen(). 00161 }; 00162 00163 #ifdef __GLIBC__ 00164 static inline void * reallocf(void *ptr, size_t size) { 00165 void *rv = realloc(ptr, size); 00166 if((rv == NULL) && (size != 0)) 00167 free(ptr); 00168 return rv; 00169 } 00170 #endif 00171 00172 freebsd_smart_device::~freebsd_smart_device() throw() 00173 { 00174 if (m_fd >= 0) 00175 os_freebsd::freebsd_smart_device::close(); 00176 } 00177 00178 // migration from the old_style 00179 unsigned char m_controller_type; 00180 unsigned char m_controller_port; 00181 00182 // examples for smartctl 00183 static const char smartctl_examples[] = 00184 "=================================================== SMARTCTL EXAMPLES =====\n\n" 00185 " smartctl -a /dev/ad0 (Prints all SMART information)\n\n" 00186 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n" 00187 " (Enables SMART on first disk)\n\n" 00188 " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n\n" 00189 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n" 00190 " (Prints Self-Test & Attribute errors)\n" 00191 " (Prints Self-Test & Attribute errors)\n\n" 00192 " smartctl -a --device=3ware,2 /dev/twa0\n" 00193 " smartctl -a --device=3ware,2 /dev/twe0\n" 00194 " smartctl -a --device=3ware,2 /dev/tws0\n" 00195 " (Prints all SMART information for ATA disk on\n" 00196 " third port of first 3ware RAID controller)\n" 00197 " smartctl -a --device=cciss,0 /dev/ciss0\n" 00198 " (Prints all SMART information for first disk \n" 00199 " on Common Interface for SCSI-3 Support driver)\n" 00200 " smartctl -a --device=areca,3/1 /dev/arcmsr0\n" 00201 " (Prints all SMART information for 3rd disk in the 1st enclosure \n" 00202 " on first ARECA RAID controller)\n" 00203 00204 ; 00205 00206 bool freebsd_smart_device::is_open() const 00207 { 00208 return (m_fd >= 0); 00209 } 00210 00211 00212 bool freebsd_smart_device::open() 00213 { 00214 const char *dev = get_dev_name(); 00215 if ((m_fd = ::open(dev,O_RDONLY))<0) { 00216 set_err(errno); 00217 return false; 00218 } 00219 return true; 00220 } 00221 00222 bool freebsd_smart_device::close() 00223 { 00224 int failed = 0; 00225 // close device, if open 00226 if (is_open()) 00227 failed=::close(get_fd()); 00228 00229 set_fd(-1); 00230 00231 if(failed) return false; 00232 else return true; 00233 } 00234 00235 ///////////////////////////////////////////////////////////////////////////// 00236 /// Implement standard ATA support 00237 00238 class freebsd_ata_device 00239 : public /*implements*/ ata_device, 00240 public /*extends*/ freebsd_smart_device 00241 { 00242 public: 00243 freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); 00244 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 00245 00246 protected: 00247 virtual int do_cmd(struct ata_ioc_request* request, bool is_48bit_cmd); 00248 }; 00249 00250 freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) 00251 : smart_device(intf, dev_name, "ata", req_type), 00252 freebsd_smart_device("ATA") 00253 { 00254 } 00255 00256 int freebsd_ata_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd) 00257 { 00258 int fd = get_fd(), ret; 00259 ARGUSED(is_48bit_cmd); // no support for 48 bit commands in the IOCATAREQUEST 00260 ret = ioctl(fd, IOCATAREQUEST, request); 00261 if (ret) set_err(errno); 00262 return ret; 00263 } 00264 00265 00266 00267 bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 00268 { 00269 bool ata_48bit = false; // no ata_48bit_support via IOCATAREQUEST 00270 if(!strcmp("atacam",get_dev_type())) // enable for atacam interface 00271 ata_48bit = true; 00272 00273 if (!ata_cmd_is_ok(in, 00274 true, // data_out_support 00275 true, // multi_sector_support 00276 ata_48bit) 00277 ) { 00278 set_err(ENOSYS, "48-bit ATA commands not implemented for legacy controllers"); 00279 return false; 00280 } 00281 00282 struct ata_ioc_request request; 00283 bzero(&request,sizeof(struct ata_ioc_request)); 00284 00285 request.timeout=SCSI_TIMEOUT_DEFAULT; 00286 request.u.ata.command=in.in_regs.command; 00287 request.u.ata.feature=in.in_regs.features; 00288 00289 request.u.ata.count = in.in_regs.sector_count_16; 00290 request.u.ata.lba = in.in_regs.lba_48; 00291 00292 switch (in.direction) { 00293 case ata_cmd_in::no_data: 00294 request.flags=ATA_CMD_CONTROL; 00295 break; 00296 case ata_cmd_in::data_in: 00297 request.flags=ATA_CMD_READ | ATA_CMD_CONTROL; 00298 request.data=(char *)in.buffer; 00299 request.count=in.size; 00300 break; 00301 case ata_cmd_in::data_out: 00302 request.flags=ATA_CMD_WRITE | ATA_CMD_CONTROL; 00303 request.data=(char *)in.buffer; 00304 request.count=in.size; 00305 break; 00306 default: 00307 return set_err(ENOSYS); 00308 } 00309 00310 clear_err(); 00311 errno = 0; 00312 if (do_cmd(&request, in.in_regs.is_48bit_cmd())) 00313 return false; 00314 if (request.error) 00315 return set_err(EIO, "request failed, error code 0x%02x", request.error); 00316 00317 out.out_regs.error = request.error; 00318 out.out_regs.sector_count_16 = request.u.ata.count; 00319 out.out_regs.lba_48 = request.u.ata.lba; 00320 00321 00322 // Command specific processing 00323 if (in.in_regs.command == ATA_SMART_CMD 00324 && in.in_regs.features == ATA_SMART_STATUS 00325 && in.out_needed.lba_high) 00326 { 00327 unsigned const char normal_lo=0x4f, normal_hi=0xc2; 00328 unsigned const char failed_lo=0xf4, failed_hi=0x2c; 00329 00330 // Cyl low and Cyl high unchanged means "Good SMART status" 00331 if (!(out.out_regs.lba_mid==normal_lo && out.out_regs.lba_high==normal_hi) 00332 // These values mean "Bad SMART status" 00333 && !(out.out_regs.lba_mid==failed_lo && out.out_regs.lba_high==failed_hi)) 00334 00335 { 00336 // We haven't gotten output that makes sense; print out some debugging info 00337 char buf[512]; 00338 snprintf(buf, sizeof(buf), 00339 "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", 00340 (int)request.u.ata.command, 00341 (int)request.u.ata.feature, 00342 (int)request.u.ata.count, 00343 (int)((request.u.ata.lba) & 0xff), 00344 (int)((request.u.ata.lba>>8) & 0xff), 00345 (int)((request.u.ata.lba>>16) & 0xff), 00346 (int)request.error); 00347 printwarning(BAD_SMART,buf); 00348 out.out_regs.lba_high = failed_hi; 00349 out.out_regs.lba_mid = failed_lo; 00350 } 00351 } 00352 00353 return true; 00354 } 00355 00356 #if FREEBSDVER > 800100 00357 class freebsd_atacam_device : public freebsd_ata_device 00358 { 00359 public: 00360 freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type) 00361 : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type) 00362 {} 00363 00364 virtual bool open(); 00365 virtual bool close(); 00366 00367 protected: 00368 int m_fd; 00369 struct cam_device *m_camdev; 00370 00371 virtual int do_cmd( struct ata_ioc_request* request , bool is_48bit_cmd); 00372 }; 00373 00374 bool freebsd_atacam_device::open(){ 00375 const char *dev = get_dev_name(); 00376 00377 if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) { 00378 set_err(errno); 00379 return false; 00380 } 00381 set_fd(m_camdev->fd); 00382 return true; 00383 } 00384 00385 bool freebsd_atacam_device::close(){ 00386 cam_close_device(m_camdev); 00387 set_fd(-1); 00388 return true; 00389 } 00390 00391 int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd) 00392 { 00393 union ccb ccb; 00394 int camflags; 00395 00396 // FIXME: 00397 // 48bit commands are broken in ATACAM before r242422/HEAD 00398 // and may cause system hang 00399 // Waiting for MFC to make sure that bug is fixed, 00400 // later version check needs to be added 00401 if(!strcmp("ata",m_camdev->sim_name) && is_48bit_cmd) { 00402 set_err(ENOSYS, "48-bit ATA commands not implemented for legacy controllers"); 00403 return -1; 00404 } 00405 00406 memset(&ccb, 0, sizeof(ccb)); 00407 00408 if (request->count == 0) 00409 camflags = CAM_DIR_NONE; 00410 else if (request->flags & ATA_CMD_READ) 00411 camflags = CAM_DIR_IN; 00412 else 00413 camflags = CAM_DIR_OUT; 00414 00415 cam_fill_ataio(&ccb.ataio, 00416 0, 00417 NULL, 00418 camflags, 00419 MSG_SIMPLE_Q_TAG, 00420 (u_int8_t*)request->data, 00421 request->count, 00422 request->timeout * 1000); // timeout in seconds 00423 00424 ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT | 00425 (is_48bit_cmd ? CAM_ATAIO_48BIT : 0); 00426 // ata_28bit_cmd 00427 ccb.ataio.cmd.command = request->u.ata.command; 00428 ccb.ataio.cmd.features = request->u.ata.feature; 00429 ccb.ataio.cmd.lba_low = request->u.ata.lba; 00430 ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8; 00431 ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16; 00432 // ata_48bit cmd 00433 ccb.ataio.cmd.lba_low_exp = request->u.ata.lba >> 24; 00434 ccb.ataio.cmd.lba_mid_exp = request->u.ata.lba >> 32; 00435 ccb.ataio.cmd.lba_high_exp = request->u.ata.lba >> 40; 00436 ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f); 00437 ccb.ataio.cmd.sector_count = request->u.ata.count; 00438 ccb.ataio.cmd.sector_count_exp = request->u.ata.count >> 8;; 00439 00440 ccb.ccb_h.flags |= CAM_DEV_QFRZDIS; 00441 00442 if (cam_send_ccb(m_camdev, &ccb) < 0) { 00443 set_err(EIO, "cam_send_ccb failed"); 00444 return -1; 00445 } 00446 00447 if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 00448 cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); 00449 set_err(EIO); 00450 return -1; 00451 } 00452 00453 request->u.ata.lba = 00454 ((u_int64_t)(ccb.ataio.res.lba_low)) | 00455 ((u_int64_t)(ccb.ataio.res.lba_mid) << 8) | 00456 ((u_int64_t)(ccb.ataio.res.lba_high) << 16) | 00457 ((u_int64_t)(ccb.ataio.res.lba_low_exp) << 24) | 00458 ((u_int64_t)(ccb.ataio.res.lba_mid_exp) << 32) | 00459 ((u_int64_t)(ccb.ataio.res.lba_high_exp) << 40); 00460 00461 request->u.ata.count = ccb.ataio.res.sector_count | (ccb.ataio.res.sector_count_exp << 8); 00462 request->error = ccb.ataio.res.error; 00463 00464 return 0; 00465 } 00466 00467 #endif 00468 00469 ///////////////////////////////////////////////////////////////////////////// 00470 /// Implement AMCC/3ware RAID support 00471 00472 class freebsd_escalade_device 00473 : public /*implements*/ ata_device, 00474 public /*extends*/ freebsd_smart_device 00475 { 00476 public: 00477 freebsd_escalade_device(smart_interface * intf, const char * dev_name, 00478 int escalade_type, int disknum); 00479 00480 protected: 00481 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); 00482 virtual bool open(); 00483 00484 private: 00485 int m_escalade_type; ///< Type string for escalade_command_interface(). 00486 int m_disknum; ///< Disk number. 00487 }; 00488 00489 freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name, 00490 int escalade_type, int disknum) 00491 : smart_device(intf, dev_name, "3ware", "3ware"), 00492 freebsd_smart_device( 00493 escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" : 00494 escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" : 00495 /* CONTROLLER_3WARE_678K */ "ATA" ), 00496 m_escalade_type(escalade_type), m_disknum(disknum) 00497 { 00498 set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum); 00499 } 00500 00501 bool freebsd_escalade_device::open() 00502 { 00503 const char *dev = get_dev_name(); 00504 int fd; 00505 00506 if ((fd = ::open(dev,O_RDWR))<0) { 00507 set_err(errno); 00508 return false; 00509 } 00510 set_fd(fd); 00511 return true; 00512 } 00513 00514 bool freebsd_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) 00515 { 00516 // to hold true file descriptor 00517 int fd = get_fd(); 00518 00519 if (!ata_cmd_is_ok(in, 00520 true, // data_out_support 00521 false, // TODO: multi_sector_support 00522 true) // ata_48bit_support 00523 ) 00524 return false; 00525 00526 struct twe_usercommand* cmd_twe = NULL; 00527 TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL; 00528 TWE_Command_ATA* ata = NULL; 00529 00530 // Used by both the SCSI and char interfaces 00531 char ioctl_buffer[TW_IOCTL_BUFFER_SIZE]; 00532 00533 if (m_disknum < 0) { 00534 printwarning(NO_DISK_3WARE,NULL); 00535 return -1; 00536 } 00537 00538 memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE); 00539 00540 if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { 00541 cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer; 00542 cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf; 00543 cmd_twa->driver_pkt.buffer_length = in.size; 00544 // using "old" packet format to speak with SATA devices 00545 ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k; 00546 } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 00547 cmd_twe = (struct twe_usercommand*)ioctl_buffer; 00548 ata = &cmd_twe->tu_command.ata; 00549 } else { 00550 return set_err(ENOSYS, 00551 "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" 00552 "Please contact " PACKAGE_BUGREPORT "\n", (int)m_escalade_type, m_disknum); 00553 } 00554 00555 ata->opcode = TWE_OP_ATA_PASSTHROUGH; 00556 00557 // Same for (almost) all commands - but some reset below 00558 ata->request_id = 0xFF; 00559 ata->unit = m_disknum; 00560 ata->status = 0; 00561 ata->flags = 0x1; 00562 ata->size = 0x5; // TODO: multisector support 00563 // Set registers 00564 { 00565 const ata_in_regs_48bit & r = in.in_regs; 00566 ata->features = r.features_16; 00567 ata->sector_count = r.sector_count_16; 00568 ata->sector_num = r.lba_low_16; 00569 ata->cylinder_lo = r.lba_mid_16; 00570 ata->cylinder_hi = r.lba_high_16; 00571 ata->drive_head = r.device; 00572 ata->command = r.command; 00573 } 00574 00575 // Is this a command that reads or returns 512 bytes? 00576 // passthru->param values are: 00577 // 0x0 - non data command without TFR write check, 00578 // 0x8 - non data command with TFR write check, 00579 // 0xD - data command that returns data to host from device 00580 // 0xF - data command that writes data from host to device 00581 // passthru->size values are 0x5 for non-data and 0x07 for data 00582 bool readdata = false; 00583 if (in.direction == ata_cmd_in::data_in) { 00584 if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 00585 cmd_twe->tu_data = in.buffer; 00586 cmd_twe->tu_size = 512; 00587 } 00588 00589 readdata=true; 00590 ata->sgl_offset = 0x5; 00591 ata->param = 0xD; 00592 // For 64-bit to work correctly, up the size of the command packet 00593 // in dwords by 1 to account for the 64-bit single sgl 'address' 00594 // field. Note that this doesn't agree with the typedefs but it's 00595 // right (agree with kernel driver behavior/typedefs). 00596 // if (sizeof(long)==8) 00597 // ata->size++; 00598 } 00599 else if (in.direction == ata_cmd_in::no_data) { 00600 // Non data command -- but doesn't use large sector 00601 // count register values. 00602 ata->sgl_offset = 0x0; 00603 ata->param = 0x8; 00604 ata->sector_count = 0x0; 00605 } 00606 else if (in.direction == ata_cmd_in::data_out) { 00607 ata->sgl_offset = 0x5; 00608 ata->param = 0xF; // PIO data write 00609 if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 00610 cmd_twe->tu_data = in.buffer; 00611 cmd_twe->tu_size = 512; 00612 } 00613 else if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { 00614 memcpy(cmd_twa->pdata, in.buffer, in.size); 00615 } 00616 } 00617 else 00618 return set_err(EINVAL); 00619 00620 // 3WARE controller can NOT have packet device internally 00621 if (in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE) { 00622 return set_err(ENODEV, "No drive on port %d", m_disknum); 00623 } 00624 00625 // Now send the command down through an ioctl() 00626 int ioctlreturn; 00627 if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { 00628 ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa); 00629 } else { 00630 ioctlreturn=ioctl(fd,TWEIO_COMMAND,cmd_twe); 00631 } 00632 00633 // Deal with the different error cases 00634 if (ioctlreturn) { 00635 return set_err(EIO); 00636 } 00637 00638 // See if the ATA command failed. Now that we have returned from 00639 // the ioctl() call, if passthru is valid, then: 00640 // - ata->status contains the 3ware controller STATUS 00641 // - ata->command contains the ATA STATUS register 00642 // - ata->features contains the ATA ERROR register 00643 // 00644 // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS 00645 // If bit 0 (error bit) is set, then ATA ERROR register is valid. 00646 // While we *might* decode the ATA ERROR register, at the moment it 00647 // doesn't make much sense: we don't care in detail why the error 00648 // happened. 00649 00650 if (ata->status || (ata->command & 0x21)) { 00651 if (scsi_debugmode) 00652 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); 00653 return set_err(EIO); 00654 } 00655 00656 // If this is a read data command, copy data to output buffer 00657 if (readdata) { 00658 if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) 00659 memcpy(in.buffer, cmd_twa->pdata, in.size); 00660 else if(m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { 00661 memcpy(in.buffer, cmd_twe->tu_data, in.size); // untested 00662 } 00663 } 00664 // Return register values 00665 if (ata) { 00666 ata_out_regs_48bit & r = out.out_regs; 00667 r.error = ata->features; 00668 r.sector_count_16 = ata->sector_count; 00669 r.lba_low_16 = ata->sector_num; 00670 r.lba_mid_16 = ata->cylinder_lo; 00671 r.lba_high_16 = ata->cylinder_hi; 00672 r.device = ata->drive_head; 00673 r.status = ata->command; 00674 } 00675 // look for nonexistent devices/ports 00676 if (in.in_regs.command == ATA_IDENTIFY_DEVICE 00677 && !nonempty((unsigned char *)in.buffer, in.size)) { 00678 return set_err(ENODEV, "No drive on port %d", m_disknum); 00679 } 00680 return true; 00681 } 00682 00683 00684 ///////////////////////////////////////////////////////////////////////////// 00685 /// Implement Highpoint RAID support with old functions 00686 00687 class freebsd_highpoint_device 00688 : public /*implements*/ ata_device_with_command_set, 00689 public /*extends*/ freebsd_smart_device 00690 { 00691 public: 00692 freebsd_highpoint_device(smart_interface * intf, const char * dev_name, 00693 unsigned char controller, unsigned char channel, unsigned char port); 00694 00695 protected: 00696 virtual int ata_command_interface(smart_command_set command, int select, char * data); 00697 virtual bool open(); 00698 00699 private: 00700 unsigned char m_hpt_data[3]; ///< controller/channel/port 00701 }; 00702 00703 00704 freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name, 00705 unsigned char controller, unsigned char channel, unsigned char port) 00706 : smart_device(intf, dev_name, "hpt", "hpt"), 00707 freebsd_smart_device("ATA") 00708 { 00709 m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port; 00710 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]); 00711 } 00712 00713 bool freebsd_highpoint_device::open() 00714 { 00715 const char *dev = get_dev_name(); 00716 int fd; 00717 00718 if ((fd = ::open(dev,O_RDWR))<0) { 00719 set_err(errno); 00720 return false; 00721 } 00722 set_fd(fd); 00723 return true; 00724 } 00725 00726 int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data) 00727 { 00728 int fd=get_fd(); 00729 int ids[2]; 00730 HPT_IOCTL_PARAM param; 00731 HPT_CHANNEL_INFO_V2 info; 00732 unsigned char* buff[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)]; 00733 PHPT_PASS_THROUGH_HEADER pide_pt_hdr, pide_pt_hdr_out; 00734 00735 // get internal deviceid 00736 ids[0] = m_hpt_data[0] - 1; 00737 ids[1] = m_hpt_data[1] - 1; 00738 00739 memset(¶m, 0, sizeof(HPT_IOCTL_PARAM)); 00740 00741 param.magic = HPT_IOCTL_MAGIC; 00742 param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO_V2; 00743 param.in = (unsigned char *)ids; 00744 param.in_size = sizeof(unsigned int) * 2; 00745 param.out = (unsigned char *)&info; 00746 param.out_size = sizeof(HPT_CHANNEL_INFO_V2); 00747 00748 if (m_hpt_data[2]==1) { 00749 param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO; 00750 param.out_size = sizeof(HPT_CHANNEL_INFO); 00751 } 00752 if (ioctl(fd, HPT_DO_IOCONTROL, ¶m)!=0 || 00753 info.devices[m_hpt_data[2]-1]==0) { 00754 return -1; 00755 } 00756 00757 // perform smart action 00758 memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)); 00759 pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff; 00760 00761 pide_pt_hdr->lbamid = 0x4f; 00762 pide_pt_hdr->lbahigh = 0xc2; 00763 pide_pt_hdr->command = ATA_SMART_CMD; 00764 pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1]; 00765 00766 switch (command){ 00767 case READ_VALUES: 00768 pide_pt_hdr->feature=ATA_SMART_READ_VALUES; 00769 pide_pt_hdr->protocol=HPT_READ; 00770 break; 00771 case READ_THRESHOLDS: 00772 pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS; 00773 pide_pt_hdr->protocol=HPT_READ; 00774 break; 00775 case READ_LOG: 00776 pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR; 00777 pide_pt_hdr->lbalow=select; 00778 pide_pt_hdr->protocol=HPT_READ; 00779 break; 00780 case IDENTIFY: 00781 pide_pt_hdr->command=ATA_IDENTIFY_DEVICE; 00782 pide_pt_hdr->protocol=HPT_READ; 00783 break; 00784 case ENABLE: 00785 pide_pt_hdr->feature=ATA_SMART_ENABLE; 00786 break; 00787 case DISABLE: 00788 pide_pt_hdr->feature=ATA_SMART_DISABLE; 00789 break; 00790 case AUTO_OFFLINE: 00791 pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE; 00792 pide_pt_hdr->sectorcount=select; 00793 break; 00794 case AUTOSAVE: 00795 pide_pt_hdr->feature=ATA_SMART_AUTOSAVE; 00796 pide_pt_hdr->sectorcount=select; 00797 break; 00798 case IMMEDIATE_OFFLINE: 00799 pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE; 00800 pide_pt_hdr->lbalow=select; 00801 break; 00802 case STATUS_CHECK: 00803 case STATUS: 00804 pide_pt_hdr->feature=ATA_SMART_STATUS; 00805 break; 00806 case CHECK_POWER_MODE: 00807 pide_pt_hdr->command=ATA_CHECK_POWER_MODE; 00808 break; 00809 case WRITE_LOG: 00810 memcpy(buff+sizeof(HPT_PASS_THROUGH_HEADER), data, 512); 00811 pide_pt_hdr->feature=ATA_SMART_WRITE_LOG_SECTOR; 00812 pide_pt_hdr->lbalow=select; 00813 pide_pt_hdr->protocol=HPT_WRITE; 00814 break; 00815 default: 00816 pout("Unrecognized command %d in highpoint_command_interface()\n" 00817 "Please contact " PACKAGE_BUGREPORT "\n", command); 00818 errno=ENOSYS; 00819 return -1; 00820 } 00821 if (pide_pt_hdr->protocol!=0) { 00822 pide_pt_hdr->sectors = 1; 00823 pide_pt_hdr->sectorcount = 1; 00824 } 00825 00826 memset(¶m, 0, sizeof(HPT_IOCTL_PARAM)); 00827 00828 param.magic = HPT_IOCTL_MAGIC; 00829 param.ctrl_code = HPT_IOCTL_IDE_PASS_THROUGH; 00830 param.in = (unsigned char *)buff; 00831 param.in_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? 0 : pide_pt_hdr->sectors * 512); 00832 param.out = (unsigned char *)buff+param.in_size; 00833 param.out_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? pide_pt_hdr->sectors * 512 : 0); 00834 00835 pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out; 00836 00837 if ((ioctl(fd, HPT_DO_IOCONTROL, ¶m)!=0) || 00838 (pide_pt_hdr_out->command & 1)) { 00839 return -1; 00840 } 00841 00842 if (command==STATUS_CHECK) 00843 { 00844 unsigned const char normal_lo=0x4f, normal_hi=0xc2; 00845 unsigned const char failed_lo=0xf4, failed_hi=0x2c; 00846 unsigned char low,high; 00847 00848 high = pide_pt_hdr_out->lbahigh; 00849 low = pide_pt_hdr_out->lbamid; 00850 00851 // Cyl low and Cyl high unchanged means "Good SMART status" 00852 if (low==normal_lo && high==normal_hi) 00853 return 0; 00854 00855 // These values mean "Bad SMART status" 00856 if (low==failed_lo && high==failed_hi) 00857 return 1; 00858 00859 // We haven't gotten output that makes sense; print out some debugging info 00860 char buf[512]; 00861 snprintf(buf, sizeof(buf), 00862 "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", 00863 (int)pide_pt_hdr_out->command, 00864 (int)pide_pt_hdr_out->feature, 00865 (int)pide_pt_hdr_out->sectorcount, 00866 (int)pide_pt_hdr_out->lbalow, 00867 (int)pide_pt_hdr_out->lbamid, 00868 (int)pide_pt_hdr_out->lbahigh, 00869 (int)pide_pt_hdr_out->sectors); 00870 printwarning(BAD_SMART,buf); 00871 } 00872 else if (command==CHECK_POWER_MODE) 00873 data[0] = pide_pt_hdr_out->sectorcount & 0xff; 00874 else if (pide_pt_hdr->protocol==HPT_READ) 00875 memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER), 00876 pide_pt_hdr->sectors * 512); 00877 return 0; 00878 } 00879 00880 00881 ///////////////////////////////////////////////////////////////////////////// 00882 /// Standard SCSI support 00883 00884 class freebsd_scsi_device 00885 : public /*implements*/ scsi_device, 00886 public /*extends*/ freebsd_smart_device 00887 { 00888 public: 00889 freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); 00890 00891 virtual smart_device * autodetect_open(); 00892 00893 virtual bool scsi_pass_through(scsi_cmnd_io * iop); 00894 00895 virtual bool open(); 00896 00897 virtual bool close(); 00898 00899 private: 00900 int m_fd; 00901 struct cam_device *m_camdev; 00902 }; 00903 00904 bool freebsd_scsi_device::open(){ 00905 const char *dev = get_dev_name(); 00906 00907 if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) { 00908 set_err(errno); 00909 return false; 00910 } 00911 set_fd(m_camdev->fd); 00912 return true; 00913 } 00914 00915 bool freebsd_scsi_device::close(){ 00916 cam_close_device(m_camdev); 00917 set_fd(-1); 00918 return true; 00919 } 00920 00921 freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf, 00922 const char * dev_name, const char * req_type) 00923 : smart_device(intf, dev_name, "scsi", req_type), 00924 freebsd_smart_device("SCSI") 00925 { 00926 } 00927 00928 00929 bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) 00930 { 00931 int report=scsi_debugmode; 00932 union ccb *ccb; 00933 00934 if (report > 0) { 00935 unsigned int k; 00936 const unsigned char * ucp = iop->cmnd; 00937 const char * np; 00938 00939 np = scsi_get_opcode_name(ucp[0]); 00940 pout(" [%s: ", np ? np : "<unknown opcode>"); 00941 for (k = 0; k < iop->cmnd_len; ++k) 00942 pout("%02x ", ucp[k]); 00943 if ((report > 1) && 00944 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { 00945 int trunc = (iop->dxfer_len > 256) ? 1 : 0; 00946 00947 pout("]\n Outgoing data, len=%d%s:\n", (int)iop->dxfer_len, 00948 (trunc ? " [only first 256 bytes shown]" : "")); 00949 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 00950 } 00951 else 00952 pout("]"); 00953 } 00954 00955 if(m_camdev==NULL) { 00956 warnx("error: camdev=0!"); 00957 return -ENOTTY; 00958 } 00959 00960 if (!(ccb = cam_getccb(m_camdev))) { 00961 warnx("error allocating ccb"); 00962 return -ENOMEM; 00963 } 00964 // mfi SAT layer is known to be buggy 00965 if(!strcmp("mfi",m_camdev->sim_name)) { 00966 if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { 00967 // Controller does not return ATA output registers in SAT sense data 00968 if (iop->cmnd[2] & (1 << 5)) // chk_cond 00969 return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware"); 00970 } 00971 // SMART WRITE LOG SECTOR causing media errors 00972 if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 00973 && iop->cmnd[14] == ATA_SMART_CMD && iop->cmnd[3]==0 && 00974 iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || 00975 (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 00976 && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) 00977 { 00978 if(!failuretest_permissive) 00979 return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); 00980 } 00981 } 00982 // clear out structure, except for header that was filled in for us 00983 bzero(&(&ccb->ccb_h)[1], 00984 sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); 00985 00986 cam_fill_csio(&ccb->csio, 00987 /*retrires*/ 1, 00988 /*cbfcnp*/ NULL, 00989 /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)), 00990 /* tagaction */ MSG_SIMPLE_Q_TAG, 00991 /* dataptr */ iop->dxferp, 00992 /* datalen */ iop->dxfer_len, 00993 /* senselen */ iop->max_sense_len, 00994 /* cdblen */ iop->cmnd_len, 00995 /* timout (converted to seconds) */ iop->timeout*1000); 00996 memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len); 00997 00998 if (cam_send_ccb(m_camdev,ccb) < 0) { 00999 warn("error sending SCSI ccb"); 01000 cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); 01001 cam_freeccb(ccb); 01002 return -EIO; 01003 } 01004 01005 if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) { 01006 cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); 01007 cam_freeccb(ccb); 01008 return -EIO; 01009 } 01010 01011 if (iop->sensep) { 01012 iop->resp_sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; 01013 memcpy(iop->sensep,&(ccb->csio.sense_data),iop->resp_sense_len); 01014 } 01015 01016 iop->scsi_status = ccb->csio.scsi_status; 01017 01018 cam_freeccb(ccb); 01019 01020 if (report > 0) { 01021 int trunc; 01022 01023 pout(" status=0\n"); 01024 trunc = (iop->dxfer_len > 256) ? 1 : 0; 01025 01026 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, 01027 (trunc ? " [only first 256 bytes shown]" : "")); 01028 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 01029 } 01030 01031 // mfip replacing PDT of the device so response does not make a sense 01032 // this sets PDT to 00h - direct-access block device 01033 if((!strcmp("mfi", m_camdev->sim_name) || !strcmp("mpt", m_camdev->sim_name)) 01034 && iop->cmnd[0] == INQUIRY) { 01035 if (report > 0) { 01036 pout("device on %s controller, patching PDT\n", m_camdev->sim_name); 01037 } 01038 iop->dxferp[0] = iop->dxferp[0] & 0xe0; 01039 } 01040 01041 return true; 01042 } 01043 01044 01045 ///////////////////////////////////////////////////////////////////////////// 01046 /// Areca RAID support 01047 01048 /////////////////////////////////////////////////////////////////// 01049 // SATA(ATA) device behind Areca RAID Controller 01050 class freebsd_areca_ata_device 01051 : public /*implements*/ areca_ata_device, 01052 public /*extends*/ freebsd_smart_device 01053 { 01054 public: 01055 freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); 01056 virtual smart_device * autodetect_open(); 01057 virtual bool arcmsr_lock(); 01058 virtual bool arcmsr_unlock(); 01059 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); 01060 }; 01061 01062 /////////////////////////////////////////////////////////////////// 01063 // SAS(SCSI) device behind Areca RAID Controller 01064 class freebsd_areca_scsi_device 01065 : public /*implements*/ areca_scsi_device, 01066 public /*extends*/ freebsd_smart_device 01067 { 01068 public: 01069 freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); 01070 virtual smart_device * autodetect_open(); 01071 virtual bool arcmsr_lock(); 01072 virtual bool arcmsr_unlock(); 01073 virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); 01074 }; 01075 01076 01077 // Areca RAID Controller(SATA Disk) 01078 freebsd_areca_ata_device::freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) 01079 : smart_device(intf, dev_name, "areca", "areca"), 01080 freebsd_smart_device("ATA") 01081 { 01082 set_disknum(disknum); 01083 set_encnum(encnum); 01084 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); 01085 } 01086 01087 01088 smart_device * freebsd_areca_ata_device::autodetect_open() 01089 { 01090 int is_ata = 1; 01091 01092 // autodetect device type 01093 is_ata = arcmsr_get_dev_type(); 01094 if(is_ata < 0) 01095 { 01096 set_err(EIO); 01097 return this; 01098 } 01099 01100 if(is_ata == 1) 01101 { 01102 // SATA device 01103 return this; 01104 } 01105 01106 // SAS device 01107 smart_device_auto_ptr newdev(new freebsd_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum())); 01108 close(); 01109 delete this; 01110 newdev->open(); // TODO: Can possibly pass open fd 01111 01112 return newdev.release(); 01113 } 01114 01115 int freebsd_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) 01116 { 01117 int ioctlreturn = 0; 01118 01119 if(!is_open()) { 01120 if(!open()){ 01121 } 01122 } 01123 01124 ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp); 01125 if (ioctlreturn) 01126 { 01127 // errors found 01128 return -1; 01129 } 01130 01131 return ioctlreturn; 01132 } 01133 01134 bool freebsd_areca_ata_device::arcmsr_lock() 01135 { 01136 return true; 01137 } 01138 01139 01140 bool freebsd_areca_ata_device::arcmsr_unlock() 01141 { 01142 return true; 01143 } 01144 01145 01146 // Areca RAID Controller(SAS Device) 01147 freebsd_areca_scsi_device::freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) 01148 : smart_device(intf, dev_name, "areca", "areca"), 01149 freebsd_smart_device("SCSI") 01150 { 01151 set_disknum(disknum); 01152 set_encnum(encnum); 01153 set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); 01154 } 01155 01156 smart_device * freebsd_areca_scsi_device::autodetect_open() 01157 { 01158 return this; 01159 } 01160 01161 int freebsd_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) 01162 { 01163 int ioctlreturn = 0; 01164 01165 if(!is_open()) { 01166 if(!open()){ 01167 } 01168 } 01169 ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp); 01170 if (ioctlreturn) 01171 { 01172 // errors found 01173 return -1; 01174 } 01175 01176 return ioctlreturn; 01177 } 01178 01179 bool freebsd_areca_scsi_device::arcmsr_lock() 01180 { 01181 return true; 01182 } 01183 01184 01185 bool freebsd_areca_scsi_device::arcmsr_unlock() 01186 { 01187 return true; 01188 } 01189 01190 01191 ///////////////////////////////////////////////////////////////////////////// 01192 /// Implement CCISS RAID support with old functions 01193 01194 class freebsd_cciss_device 01195 : public /*implements*/ scsi_device, 01196 public /*extends*/ freebsd_smart_device 01197 { 01198 public: 01199 freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum); 01200 01201 virtual bool scsi_pass_through(scsi_cmnd_io * iop); 01202 virtual bool open(); 01203 01204 private: 01205 unsigned char m_disknum; ///< Disk number. 01206 }; 01207 01208 bool freebsd_cciss_device::open() 01209 { 01210 const char *dev = get_dev_name(); 01211 int fd; 01212 if ((fd = ::open(dev,O_RDWR))<0) { 01213 set_err(errno); 01214 return false; 01215 } 01216 set_fd(fd); 01217 return true; 01218 } 01219 01220 freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf, 01221 const char * dev_name, unsigned char disknum) 01222 : smart_device(intf, dev_name, "cciss", "cciss"), 01223 freebsd_smart_device("SCSI"), 01224 m_disknum(disknum) 01225 { 01226 set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum); 01227 } 01228 01229 bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop) 01230 { 01231 int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode); 01232 if (status < 0) 01233 return set_err(-status); 01234 return true; 01235 // not reached 01236 return true; 01237 } 01238 01239 01240 ///////////////////////////////////////////////////////////////////////////// 01241 /// SCSI open with autodetection support 01242 01243 smart_device * freebsd_scsi_device::autodetect_open() 01244 { 01245 // Open device 01246 if (!open()) 01247 return this; 01248 01249 // No Autodetection if device type was specified by user 01250 if (*get_req_type()) 01251 return this; 01252 01253 // The code below is based on smartd.cpp:SCSIFilterKnown() 01254 01255 // Get INQUIRY 01256 unsigned char req_buff[64] = {0, }; 01257 int req_len = 36; 01258 if (scsiStdInquiry(this, req_buff, req_len)) { 01259 // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices 01260 // watch this spot ... other devices could lock up here 01261 req_len = 64; 01262 if (scsiStdInquiry(this, req_buff, req_len)) { 01263 // device doesn't like INQUIRY commands 01264 close(); 01265 set_err(EIO, "INQUIRY failed"); 01266 return this; 01267 } 01268 } 01269 01270 int avail_len = req_buff[4] + 5; 01271 int len = (avail_len < req_len ? avail_len : req_len); 01272 if (len < 36) 01273 return this; 01274 01275 // Use INQUIRY to detect type 01276 01277 // 3ware ? 01278 if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4) || 01279 !strcmp("tws",m_camdev->sim_name) || !strcmp("twa",m_camdev->sim_name)) { 01280 close(); 01281 set_err(EINVAL, "3ware/LSI controller, please try adding '-d 3ware,N',\n" 01282 "you may need to replace %s with /dev/twaN, /dev/tweN or /dev/twsN", get_dev_name()); 01283 return this; 01284 } 01285 01286 // SAT or USB, skip MFI controllers because of bugs 01287 { 01288 smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); 01289 if (newdev) { 01290 // NOTE: 'this' is now owned by '*newdev' 01291 if(!strcmp("mfi",m_camdev->sim_name)) { 01292 newdev->close(); 01293 newdev->set_err(ENOSYS, "SATA device detected,\n" 01294 "MegaRAID SAT layer is reportedly buggy, use '-d sat' to try anyhow"); 01295 } 01296 return newdev; 01297 } 01298 } 01299 01300 // Nothing special found 01301 return this; 01302 } 01303 01304 01305 ///////////////////////////////////////////////////////////////////////////// 01306 /// Implement platform interface with old functions. 01307 01308 class freebsd_smart_interface 01309 : public /*implements*/ smart_interface 01310 { 01311 public: 01312 virtual std::string get_os_version_str(); 01313 01314 virtual std::string get_app_examples(const char * appname); 01315 01316 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, 01317 const char * pattern = 0); 01318 01319 protected: 01320 virtual ata_device * get_ata_device(const char * name, const char * type); 01321 01322 #if FREEBSDVER > 800100 01323 virtual ata_device * get_atacam_device(const char * name, const char * type); 01324 #endif 01325 01326 virtual scsi_device * get_scsi_device(const char * name, const char * type); 01327 01328 virtual smart_device * autodetect_smart_device(const char * name); 01329 01330 virtual smart_device * get_custom_smart_device(const char * name, const char * type); 01331 01332 virtual std::string get_valid_custom_dev_types_str(); 01333 }; 01334 01335 01336 ////////////////////////////////////////////////////////////////////// 01337 01338 std::string freebsd_smart_interface::get_os_version_str() 01339 { 01340 struct utsname osname; 01341 uname(&osname); 01342 return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine); 01343 } 01344 01345 std::string freebsd_smart_interface::get_app_examples(const char * appname) 01346 { 01347 if (!strcmp(appname, "smartctl")) 01348 return smartctl_examples; 01349 return ""; 01350 } 01351 01352 ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type) 01353 { 01354 return new freebsd_ata_device(this, name, type); 01355 } 01356 01357 #if FREEBSDVER > 800100 01358 ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type) 01359 { 01360 return new freebsd_atacam_device(this, name, type); 01361 } 01362 #endif 01363 01364 scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type) 01365 { 01366 return new freebsd_scsi_device(this, name, type); 01367 } 01368 01369 // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...) 01370 // devices on system despite of it's names 01371 // 01372 // If any errors occur, leave errno set as it was returned by the 01373 // system call, and return <0. 01374 // 01375 // arguments: 01376 // names: resulting array 01377 // show_all - export duplicate device name or not 01378 // 01379 // Return values: 01380 // -1: error 01381 // >=0: number of discovered devices 01382 01383 bool get_dev_names_cam(std::vector<std::string> & names, bool show_all) 01384 { 01385 int fd; 01386 if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { 01387 if (errno == ENOENT) /* There are no CAM device on this computer */ 01388 return 0; 01389 int serrno = errno; 01390 pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno)); 01391 errno = serrno; 01392 return false; 01393 } 01394 01395 union ccb ccb; 01396 bzero(&ccb, sizeof(union ccb)); 01397 01398 ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 01399 ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 01400 ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 01401 01402 ccb.ccb_h.func_code = XPT_DEV_MATCH; 01403 int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV; 01404 ccb.cdm.match_buf_len = bufsize; 01405 // TODO: Use local buffer instead of malloc() if possible 01406 ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); 01407 bzero(ccb.cdm.matches,bufsize); // clear ccb.cdm.matches structure 01408 01409 if (ccb.cdm.matches == NULL) { 01410 close(fd); 01411 throw std::bad_alloc(); 01412 } 01413 ccb.cdm.num_matches = 0; 01414 ccb.cdm.num_patterns = 0; 01415 ccb.cdm.pattern_buf_len = 0; 01416 01417 /* 01418 * We do the ioctl multiple times if necessary, in case there are 01419 * more than MAX_NUM_DEV nodes in the EDT. 01420 */ 01421 int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool 01422 std::string devname; 01423 do { 01424 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { 01425 int serrno = errno; 01426 pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno)); 01427 free(ccb.cdm.matches); 01428 close(fd); 01429 errno = serrno; 01430 return false; 01431 } 01432 01433 if ((ccb.ccb_h.status != CAM_REQ_CMP) 01434 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) 01435 && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { 01436 pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status); 01437 free(ccb.cdm.matches); 01438 close(fd); 01439 errno = ENXIO; 01440 return false; 01441 } 01442 01443 for (unsigned i = 0; i < ccb.cdm.num_matches; i++) { 01444 struct bus_match_result *bus_result; 01445 struct device_match_result *dev_result; 01446 struct periph_match_result *periph_result; 01447 01448 if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) { 01449 bus_result = &ccb.cdm.matches[i].result.bus_result; 01450 01451 if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */ 01452 skip_bus = 1; 01453 else 01454 skip_bus = 0; 01455 changed = 1; 01456 } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) { 01457 dev_result = &ccb.cdm.matches[i].result.device_result; 01458 01459 if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1) 01460 skip_device = 1; 01461 else 01462 skip_device = 0; 01463 01464 // /* Shall we skip non T_DIRECT devices ? */ 01465 // if (dev_result->inq_data.device != T_DIRECT) 01466 // skip_device = 1; 01467 changed = 1; 01468 } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && 01469 (skip_device == 0 || show_all)) { 01470 /* One device may be populated as many peripherals (pass0 & da0 for example). 01471 * We are searching for best name 01472 */ 01473 periph_result = &ccb.cdm.matches[i].result.periph_result; 01474 /* Prefer non-"pass" names */ 01475 if (devname.empty() || strncmp(periph_result->periph_name, "pass", 4) != 0) { 01476 devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number); 01477 } 01478 changed = 0; 01479 }; 01480 if ((changed == 1 || show_all) && !devname.empty()) { 01481 names.push_back(devname); 01482 devname.erase(); 01483 changed = 0; 01484 }; 01485 } 01486 01487 } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); 01488 01489 if (!devname.empty()) 01490 names.push_back(devname); 01491 01492 free(ccb.cdm.matches); 01493 close(fd); 01494 return true; 01495 } 01496 01497 // we are using ATA subsystem enumerator to found all ATA devices on system 01498 // despite of it's names 01499 // 01500 // If any errors occur, leave errno set as it was returned by the 01501 // system call, and return <0. 01502 01503 // Return values: 01504 // -1: error 01505 // >=0: number of discovered devices 01506 int get_dev_names_ata(char*** names) { 01507 struct ata_ioc_devices devices; 01508 int fd=-1,maxchannel,serrno=-1,n=0; 01509 char **mp = NULL; 01510 01511 *names=NULL; 01512 01513 if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) { 01514 if (errno == ENOENT) /* There are no ATA device on this computer */ 01515 return 0; 01516 serrno = errno; 01517 pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno)); 01518 n = -1; 01519 goto end; 01520 }; 01521 01522 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) { 01523 serrno = errno; 01524 pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno)); 01525 n = -1; 01526 goto end; 01527 }; 01528 01529 // allocate space for up to MAX_NUM_DEV number of ATA devices 01530 mp = (char **)calloc(MAX_NUM_DEV, sizeof(char*)); 01531 if (mp == NULL) { 01532 serrno=errno; 01533 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__); 01534 n = -1; 01535 goto end; 01536 }; 01537 01538 for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) { 01539 int j; 01540 01541 if (ioctl(fd, IOCATADEVICES, &devices) < 0) { 01542 if (errno == ENXIO) 01543 continue; /* such channel not exist */ 01544 pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno)); 01545 n = -1; 01546 goto end; 01547 }; 01548 for (j=0;j<=1 && n<MAX_NUM_DEV;j++) { 01549 if (devices.name[j][0] != '\0') { 01550 asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]); 01551 if (mp[n] == NULL) { 01552 pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__); 01553 n = -1; 01554 goto end; 01555 }; 01556 bytes+=1+strlen(mp[n]); 01557 n++; 01558 }; 01559 }; 01560 }; 01561 mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size 01562 if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL 01563 serrno=errno; 01564 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__); 01565 n = -1; 01566 goto end; 01567 }; 01568 bytes += (n)*(sizeof(char*)); // and set allocated byte count 01569 01570 end: 01571 if (fd>=0) 01572 close(fd); 01573 if (n <= 0) { 01574 free(mp); 01575 mp = NULL; 01576 } 01577 01578 *names=mp; 01579 01580 if (serrno>-1) 01581 errno=serrno; 01582 return n; 01583 } 01584 01585 01586 01587 bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist, 01588 const char * type, const char * pattern /*= 0*/) 01589 { 01590 if (pattern) { 01591 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); 01592 return false; 01593 } 01594 01595 // Make namelists 01596 char * * atanames = 0; int numata = 0; 01597 if (!type || !strcmp(type, "ata")) { 01598 numata = get_dev_names_ata(&atanames); 01599 if (numata < 0) { 01600 set_err(ENOMEM); 01601 return false; 01602 } 01603 } 01604 01605 std::vector<std::string> scsinames; 01606 if (!type || !strcmp(type, "scsi")) { // do not export duplicated names 01607 if (!get_dev_names_cam(scsinames, false)) { 01608 set_err(errno); 01609 return false; 01610 } 01611 } 01612 01613 // Add to devlist 01614 int i; 01615 if (type==NULL) 01616 type=""; 01617 for (i = 0; i < numata; i++) { 01618 ata_device * atadev = get_ata_device(atanames[i], type); 01619 if (atadev) 01620 devlist.push_back(atadev); 01621 free(atanames[i]); 01622 } 01623 if(numata) free(atanames); 01624 01625 for (i = 0; i < (int)scsinames.size(); i++) { 01626 if(!*type) { // try USB autodetection if no type specified 01627 smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str()); 01628 if(smartdev) 01629 devlist.push_back(smartdev); 01630 } 01631 else { 01632 scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type); 01633 if (scsidev) 01634 devlist.push_back(scsidev); 01635 } 01636 } 01637 return true; 01638 } 01639 01640 01641 #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8 01642 static char done[USB_MAX_DEVICES]; 01643 01644 static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id, 01645 unsigned short & product_id, unsigned short & version) 01646 { 01647 01648 struct usb_device_info di; 01649 int e, p, i; 01650 char devname[256]; 01651 01652 snprintf(devname, sizeof(devname),"umass%d",busno); 01653 01654 di.udi_addr = a; 01655 e = ioctl(f, USB_DEVICEINFO, &di); 01656 if (e) { 01657 if (errno != ENXIO) 01658 printf("addr %d: I/O error\n", a); 01659 return 0; 01660 } 01661 done[a] = 1; 01662 01663 // list devices 01664 for (i = 0; i < USB_MAX_DEVNAMES; i++) { 01665 if (di.udi_devnames[i][0]) { 01666 if(strcmp(di.udi_devnames[i],devname)==0) { 01667 // device found! 01668 vendor_id = di.udi_vendorNo; 01669 product_id = di.udi_productNo; 01670 version = di.udi_releaseNo; 01671 return 1; 01672 // FIXME 01673 } 01674 } 01675 } 01676 if (!rec) 01677 return 0; 01678 for (p = 0; p < di.udi_nports; p++) { 01679 int s = di.udi_ports[p]; 01680 if (s >= USB_MAX_DEVICES) { 01681 continue; 01682 } 01683 if (s == 0) 01684 printf("addr 0 should never happen!\n"); 01685 else { 01686 if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1; 01687 } 01688 } 01689 return 0; 01690 } 01691 #endif 01692 01693 01694 static int usbdevlist(int busno,unsigned short & vendor_id, 01695 unsigned short & product_id, unsigned short & version) 01696 { 01697 #if (FREEBSDVER >= 800000) // libusb2 interface 01698 struct libusb20_device *pdev = NULL; 01699 struct libusb20_backend *pbe; 01700 uint32_t matches = 0; 01701 char buf[128]; // do not change! 01702 char devname[128]; 01703 uint8_t n; 01704 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 01705 01706 pbe = libusb20_be_alloc_default(); 01707 01708 while ((pdev = libusb20_be_device_foreach(pbe, pdev))) { 01709 matches++; 01710 01711 if (libusb20_dev_open(pdev, 0)) { 01712 warnx("libusb20_dev_open: could not open device"); 01713 return 0; 01714 } 01715 01716 pdesc=libusb20_dev_get_device_desc(pdev); 01717 01718 snprintf(devname, sizeof(devname),"umass%d:",busno); 01719 for (n = 0; n != 255; n++) { 01720 if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf))) 01721 break; 01722 if (buf[0] == 0) 01723 continue; 01724 if(strncmp(buf,devname,strlen(devname))==0){ 01725 // found! 01726 vendor_id = pdesc->idVendor; 01727 product_id = pdesc->idProduct; 01728 version = pdesc->bcdDevice; 01729 libusb20_dev_close(pdev); 01730 libusb20_be_free(pbe); 01731 return 1; 01732 } 01733 } 01734 01735 libusb20_dev_close(pdev); 01736 } 01737 01738 if (matches == 0) { 01739 printf("No device match or lack of permissions.\n"); 01740 } 01741 01742 libusb20_be_free(pbe); 01743 01744 return false; 01745 #else // freebsd < 8.0 USB stack, ioctl interface 01746 01747 int i, f, a, rc; 01748 char buf[50]; 01749 int ncont; 01750 01751 for (ncont = 0, i = 0; i < 10; i++) { 01752 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i); 01753 f = open(buf, O_RDONLY); 01754 if (f >= 0) { 01755 memset(done, 0, sizeof done); 01756 for (a = 1; a < USB_MAX_DEVICES; a++) { 01757 if (!done[a]) { 01758 rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version); 01759 if(rc) return 1; 01760 } 01761 01762 } 01763 close(f); 01764 } else { 01765 if (errno == ENOENT || errno == ENXIO) 01766 continue; 01767 warn("%s", buf); 01768 } 01769 ncont++; 01770 } 01771 return 0; 01772 #endif 01773 } 01774 01775 smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name) 01776 { 01777 unsigned short vendor_id = 0, product_id = 0, version = 0; 01778 struct cam_device *cam_dev; 01779 union ccb ccb; 01780 int bus=-1; 01781 int i,c; 01782 int len; 01783 const char * test_name = name; 01784 01785 // if dev_name null, or string length zero 01786 if (!name || !(len = strlen(name))) 01787 return 0; 01788 01789 // Dereference symlinks 01790 struct stat st; 01791 std::string pathbuf; 01792 if (!lstat(name, &st) && S_ISLNK(st.st_mode)) { 01793 char * p = realpath(name, (char *)0); 01794 if (p) { 01795 pathbuf = p; 01796 free(p); 01797 test_name = pathbuf.c_str(); 01798 } 01799 } 01800 01801 // check ATA bus 01802 char * * atanames = 0; int numata = 0; 01803 numata = get_dev_names_ata(&atanames); 01804 if (numata > 0) { 01805 // check ATA/ATAPI devices 01806 for (i = 0; i < numata; i++) { 01807 if(!strcmp(atanames[i],test_name)) { 01808 for (c = i; c < numata; c++) free(atanames[c]); 01809 free(atanames); 01810 return new freebsd_ata_device(this, test_name, ""); 01811 } 01812 else free(atanames[i]); 01813 } 01814 if(numata) free(atanames); 01815 } 01816 else { 01817 if (numata < 0) 01818 pout("Unable to get ATA device list\n"); 01819 } 01820 01821 // check CAM 01822 std::vector<std::string> scsinames; 01823 if (!get_dev_names_cam(scsinames, true)) 01824 pout("Unable to get CAM device list\n"); 01825 else if (!scsinames.empty()) { 01826 // check all devices on CAM bus 01827 for (i = 0; i < (int)scsinames.size(); i++) { 01828 if(strcmp(scsinames[i].c_str(), test_name)==0) 01829 { // our disk device is CAM 01830 if ((cam_dev = cam_open_device(test_name, O_RDWR)) == NULL) { 01831 // open failure 01832 set_err(errno); 01833 return 0; 01834 } 01835 // zero the payload 01836 bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE); 01837 ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device 01838 if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) { 01839 warn("Get Transfer Settings CCB failed\n" 01840 "%s", strerror(errno)); 01841 cam_close_device(cam_dev); 01842 return 0; 01843 } 01844 // now check if we are working with USB device, see umass.c 01845 if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found 01846 usbdevlist(bus,vendor_id, product_id, version); 01847 int bus=ccb.cpi.unit_number; // unit_number will match umass number 01848 cam_close_device(cam_dev); 01849 if(usbdevlist(bus,vendor_id, product_id, version)){ 01850 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version); 01851 if (usbtype) 01852 return get_sat_device(usbtype, new freebsd_scsi_device(this, test_name, "")); 01853 } 01854 return 0; 01855 } 01856 #if FREEBSDVER > 800100 01857 // check if we have ATA device connected to CAM (ada) 01858 if(ccb.cpi.protocol == PROTO_ATA){ 01859 cam_close_device(cam_dev); 01860 return new freebsd_atacam_device(this, test_name, ""); 01861 } 01862 #endif 01863 // close cam device, we don`t need it anymore 01864 cam_close_device(cam_dev); 01865 // handle as usual scsi 01866 return new freebsd_scsi_device(this, test_name, ""); 01867 } 01868 } 01869 } 01870 // device is LSI raid supported by mfi driver 01871 if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid"))) 01872 set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information"); 01873 // device type unknown 01874 return 0; 01875 } 01876 01877 01878 smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type) 01879 { 01880 // 3Ware ? 01881 static const char * fbsd_dev_twe_ctrl = "/dev/twe"; 01882 static const char * fbsd_dev_twa_ctrl = "/dev/twa"; 01883 static const char * fbsd_dev_tws_ctrl = "/dev/tws"; 01884 int disknum = -1, n1 = -1, n2 = -1, contr = -1; 01885 01886 if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { 01887 if (n2 != (int)strlen(type)) { 01888 set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer"); 01889 return 0; 01890 } 01891 if (!(0 <= disknum && disknum <= 127)) { 01892 set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum); 01893 return 0; 01894 } 01895 01896 // guess 3ware device type based on device name 01897 if (str_starts_with(name, fbsd_dev_twa_ctrl) || 01898 str_starts_with(name, fbsd_dev_tws_ctrl) ) { 01899 contr=CONTROLLER_3WARE_9000_CHAR; 01900 } 01901 if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){ 01902 contr=CONTROLLER_3WARE_678K_CHAR; 01903 } 01904 01905 if(contr == -1){ 01906 set_err(EINVAL, "3ware controller type unknown, use %sX, %sX or %sX devices", 01907 fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl, fbsd_dev_tws_ctrl); 01908 return 0; 01909 } 01910 return new freebsd_escalade_device(this, name, contr, disknum); 01911 } 01912 01913 // Highpoint ? 01914 int controller = -1, channel = -1; disknum = 1; 01915 n1 = n2 = -1; int n3 = -1; 01916 if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) { 01917 int len = strlen(type); 01918 if (!(n2 == len || n3 == len)) { 01919 set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items"); 01920 return 0; 01921 } 01922 if (!(1 <= controller && controller <= 8)) { 01923 set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied"); 01924 return 0; 01925 } 01926 if (!(1 <= channel && channel <= 16)) { 01927 set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied"); 01928 return 0; 01929 } 01930 if (!(1 <= disknum && disknum <= 15)) { 01931 set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied"); 01932 return 0; 01933 } 01934 return new freebsd_highpoint_device(this, name, controller, channel, disknum); 01935 } 01936 01937 // CCISS ? 01938 disknum = n1 = n2 = -1; 01939 if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { 01940 if (n2 != (int)strlen(type)) { 01941 set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer"); 01942 return 0; 01943 } 01944 if (!(0 <= disknum && disknum <= 127)) { 01945 set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum); 01946 return 0; 01947 } 01948 return get_sat_device("sat,auto", new freebsd_cciss_device(this, name, disknum)); 01949 } 01950 #if FREEBSDVER > 800100 01951 // adaX devices ? 01952 if(!strcmp(type,"atacam")) 01953 return new freebsd_atacam_device(this, name, ""); 01954 #endif 01955 // Areca? 01956 disknum = n1 = n2 = -1; 01957 int encnum = 1; 01958 if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { 01959 if (!(1 <= disknum && disknum <= 128)) { 01960 set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); 01961 return 0; 01962 } 01963 if (!(1 <= encnum && encnum <= 8)) { 01964 set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); 01965 return 0; 01966 } 01967 return new freebsd_areca_ata_device(this, name, disknum, encnum); 01968 } 01969 01970 return 0; 01971 } 01972 01973 std::string freebsd_smart_interface::get_valid_custom_dev_types_str() 01974 { 01975 return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E" 01976 #if FREEBSDVER > 800100 01977 ", atacam" 01978 #endif 01979 ; 01980 } 01981 01982 } // namespace 01983 01984 ///////////////////////////////////////////////////////////////////////////// 01985 /// Initialize platform interface and register with smi() 01986 01987 void smart_interface::init() 01988 { 01989 static os_freebsd::freebsd_smart_interface the_interface; 01990 smart_interface::set(&the_interface); 01991 }
1.7.4