4 * Home page of code is: http://smartmontools.sourceforge.net
6 * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net>
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)
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.
19 #include <sys/types.h>
25 #include <cam/scsi/scsi_message.h>
26 #include <cam/scsi/scsi_pass.h>
27 #if defined(__DragonFly__)
37 #include <sys/utsname.h>
45 #include "os_freebsd.h"
47 #include "dev_interface.h"
48 #include "dev_ata_cmd_set.h"
50 #define USBDEV "/dev/usb"
51 #if defined(__FreeBSD_version)
53 // This way we define one variable for the GNU/kFreeBSD and FreeBSD
54 #define FREEBSDVER __FreeBSD_version
56 #define FREEBSDVER __FreeBSD_kernel_version
59 #if (FREEBSDVER >= 800000)
60 #include <libusb20_desc.h>
62 #elif defined(__DragonFly__)
63 #include <bus/usb/usb.h>
64 #include <bus/usb/usbhid.h>
66 #include <dev/usb/usb.h>
67 #include <dev/usb/usbhid.h>
70 #define CONTROLLER_3WARE_9000_CHAR 0x01
71 #define CONTROLLER_3WARE_678K_CHAR 0x02
73 #ifndef PATHINQ_SETTINGS_SIZE
74 #define PATHINQ_SETTINGS_SIZE 128
77 const char *os_XXXX_c_cvsid
="$Id: os_freebsd.cpp 3335 2011-05-21 17:32:16Z samm2 $" \
78 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
82 #define NO_DISK_3WARE 2
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",
92 "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE
"\nRegister values returned from SMART Status command are:\n",
94 "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
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"
99 if (msgNo
>= 0 && msgNo
<= MAX_MSG
) {
100 if (!printed
[msgNo
]) {
102 pout("%s", message
[msgNo
]);
110 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
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) )
117 #define ATA_DEVICE "/dev/ata"
120 // global variable holding byte count of allocated memory
123 /////////////////////////////////////////////////////////////////////////////
125 namespace os_freebsd
{ // No need to publish anything, name provided for Doxygen
127 /////////////////////////////////////////////////////////////////////////////
128 /// Implement shared open/close routines with old functions.
130 class freebsd_smart_device
131 : virtual public /*implements*/ smart_device
134 explicit freebsd_smart_device(const char * mode
)
135 : smart_device(never_called
),
136 m_fd(-1), m_mode(mode
) { }
138 virtual ~freebsd_smart_device() throw();
140 virtual bool is_open() const;
144 virtual bool close();
147 /// Return filedesc for derived classes.
155 int m_fd
; ///< filedesc, -1 if not open.
156 const char * m_mode
; ///< Mode string for deviceopen().
160 static inline void * reallocf(void *ptr
, size_t size
) {
161 void *rv
= realloc(ptr
, size
);
162 if((rv
== NULL
) && (size
!= 0))
168 freebsd_smart_device::~freebsd_smart_device() throw()
171 os_freebsd::freebsd_smart_device::close();
174 // migration from the old_style
175 unsigned char m_controller_type
;
176 unsigned char m_controller_port
;
178 // examples for smartctl
179 static const char smartctl_examples
[] =
180 "=================================================== SMARTCTL EXAMPLES =====\n\n"
181 " smartctl -a /dev/ad0 (Prints all SMART information)\n\n"
182 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
183 " (Enables SMART on first disk)\n\n"
184 " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n\n"
185 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
186 " (Prints Self-Test & Attribute errors)\n"
187 " (Prints Self-Test & Attribute errors)\n\n"
188 " smartctl -a --device=3ware,2 /dev/twa0\n"
189 " smartctl -a --device=3ware,2 /dev/twe0\n"
190 " (Prints all SMART information for ATA disk on\n"
191 " third port of first 3ware RAID controller)\n"
192 " smartctl -a --device=cciss,0 /dev/ciss0\n"
193 " (Prints all SMART information for first disk \n"
194 " on Common Interface for SCSI-3 Support driver)\n"
198 bool freebsd_smart_device::is_open() const
204 bool freebsd_smart_device::open()
206 const char *dev
= get_dev_name();
207 if ((m_fd
= ::open(dev
,O_RDONLY
))<0) {
214 bool freebsd_smart_device::close()
217 // close device, if open
219 failed
=::close(get_fd());
223 if(failed
) return false;
227 /////////////////////////////////////////////////////////////////////////////
228 /// Implement standard ATA support
230 class freebsd_ata_device
231 : public /*implements*/ ata_device
,
232 public /*extends*/ freebsd_smart_device
235 freebsd_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
236 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
239 virtual int do_cmd(struct ata_ioc_request
* request
);
242 freebsd_ata_device::freebsd_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
243 : smart_device(intf
, dev_name
, "ata", req_type
),
244 freebsd_smart_device("ATA")
248 int freebsd_ata_device::do_cmd( struct ata_ioc_request
* request
)
251 return ioctl(fd
, IOCATAREQUEST
, request
);
256 bool freebsd_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
258 if (!ata_cmd_is_ok(in
,
259 true, // data_out_support
260 true, // multi_sector_support
261 false) // no ata_48bit_support via IOCATAREQUEST
265 struct ata_ioc_request request
;
266 bzero(&request
,sizeof(struct ata_ioc_request
));
268 request
.timeout
=SCSI_TIMEOUT_DEFAULT
;
269 request
.u
.ata
.command
=in
.in_regs
.command
;
270 request
.u
.ata
.feature
=in
.in_regs
.features
;
272 request
.u
.ata
.count
= in
.in_regs
.sector_count_16
;
273 request
.u
.ata
.lba
= in
.in_regs
.lba_48
;
275 switch (in
.direction
) {
276 case ata_cmd_in::no_data
:
277 request
.flags
=ATA_CMD_CONTROL
;
279 case ata_cmd_in::data_in
:
280 request
.flags
=ATA_CMD_READ
;
281 request
.data
=(char *)in
.buffer
;
282 request
.count
=in
.size
;
284 case ata_cmd_in::data_out
:
285 request
.flags
=ATA_CMD_WRITE
;
286 request
.data
=(char *)in
.buffer
;
287 request
.count
=in
.size
;
290 return set_err(ENOSYS
);
295 if (do_cmd(&request
))
296 return set_err(errno
);
298 return set_err(EIO
, "request failed, error code 0x%02x", request
.error
);
300 out
.out_regs
.error
= request
.error
;
301 out
.out_regs
.sector_count_16
= request
.u
.ata
.count
;
302 out
.out_regs
.lba_48
= request
.u
.ata
.lba
;
305 // Command specific processing
306 if (in
.in_regs
.command
== ATA_SMART_CMD
307 && in
.in_regs
.features
== ATA_SMART_STATUS
308 && in
.out_needed
.lba_high
)
310 unsigned const char normal_lo
=0x4f, normal_hi
=0xc2;
311 unsigned const char failed_lo
=0xf4, failed_hi
=0x2c;
313 #if (FREEBSDVER < 502000)
314 printwarning(NO_RETURN
,NULL
);
317 // Cyl low and Cyl high unchanged means "Good SMART status"
318 if (!(out
.out_regs
.lba_mid
==normal_lo
&& out
.out_regs
.lba_high
==normal_hi
)
319 // These values mean "Bad SMART status"
320 && !(out
.out_regs
.lba_mid
==failed_lo
&& out
.out_regs
.lba_high
==failed_hi
))
323 // We haven't gotten output that makes sense; print out some debugging info
325 sprintf(buf
,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
326 (int)request
.u
.ata
.command
,
327 (int)request
.u
.ata
.feature
,
328 (int)request
.u
.ata
.count
,
329 (int)((request
.u
.ata
.lba
) & 0xff),
330 (int)((request
.u
.ata
.lba
>>8) & 0xff),
331 (int)((request
.u
.ata
.lba
>>16) & 0xff),
333 printwarning(BAD_SMART
,buf
);
334 out
.out_regs
.lba_high
= failed_hi
;
335 out
.out_regs
.lba_mid
= failed_lo
;
342 #if FREEBSDVER > 800100
343 class freebsd_atacam_device
: public freebsd_ata_device
346 freebsd_atacam_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
347 : smart_device(intf
, dev_name
, "atacam", req_type
), freebsd_ata_device(intf
, dev_name
, req_type
)
351 virtual bool close();
355 struct cam_device
*m_camdev
;
357 virtual int do_cmd( struct ata_ioc_request
* request
);
360 bool freebsd_atacam_device::open(){
361 const char *dev
= get_dev_name();
363 if ((m_camdev
= cam_open_device(dev
, O_RDWR
)) == NULL
) {
367 set_fd(m_camdev
->fd
);
371 bool freebsd_atacam_device::close(){
372 cam_close_device(m_camdev
);
377 int freebsd_atacam_device::do_cmd( struct ata_ioc_request
* request
)
382 memset(&ccb
, 0, sizeof(ccb
));
384 if (request
->count
== 0)
385 camflags
= CAM_DIR_NONE
;
386 else if (request
->flags
== ATA_CMD_READ
)
387 camflags
= CAM_DIR_IN
;
389 camflags
= CAM_DIR_OUT
;
391 cam_fill_ataio(&ccb
.ataio
,
396 (u_int8_t
*)request
->data
,
398 request
->timeout
* 1000); // timeout in seconds
401 if (request
->flags
== ATA_CMD_CONTROL
)
402 ccb
.ataio
.cmd
.flags
= CAM_ATAIO_NEEDRESULT
;
404 ccb
.ataio
.cmd
.flags
= 0;
405 ccb
.ataio
.cmd
.command
= request
->u
.ata
.command
;
406 ccb
.ataio
.cmd
.features
= request
->u
.ata
.feature
;
407 ccb
.ataio
.cmd
.lba_low
= request
->u
.ata
.lba
;
408 ccb
.ataio
.cmd
.lba_mid
= request
->u
.ata
.lba
>> 8;
409 ccb
.ataio
.cmd
.lba_high
= request
->u
.ata
.lba
>> 16;
410 ccb
.ataio
.cmd
.device
= 0x40 | ((request
->u
.ata
.lba
>> 24) & 0x0f);
411 ccb
.ataio
.cmd
.sector_count
= request
->u
.ata
.count
;
413 ccb
.ccb_h
.flags
|= CAM_DEV_QFRZDIS
;
415 if (cam_send_ccb(m_camdev
, &ccb
) < 0) {
416 err(1, "cam_send_ccb");
420 if ((ccb
.ccb_h
.status
& CAM_STATUS_MASK
) != CAM_REQ_CMP
) {
421 cam_error_print(m_camdev
, &ccb
, CAM_ESF_ALL
, CAM_EPF_ALL
, stderr
);
425 request
->u
.ata
.count
= ccb
.ataio
.res
.sector_count
;
431 /////////////////////////////////////////////////////////////////////////////
432 /// Implement AMCC/3ware RAID support with old functions
434 class freebsd_escalade_device
435 : public /*implements*/ ata_device_with_command_set
,
436 public /*extends*/ freebsd_smart_device
439 freebsd_escalade_device(smart_interface
* intf
, const char * dev_name
,
440 int escalade_type
, int disknum
);
443 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
447 int m_escalade_type
; ///< Type string for escalade_command_interface().
448 int m_disknum
; ///< Disk number.
451 freebsd_escalade_device::freebsd_escalade_device(smart_interface
* intf
, const char * dev_name
,
452 int escalade_type
, int disknum
)
453 : smart_device(intf
, dev_name
, "3ware", "3ware"),
454 freebsd_smart_device(
455 escalade_type
==CONTROLLER_3WARE_9000_CHAR
? "ATA_3WARE_9000" :
456 escalade_type
==CONTROLLER_3WARE_678K_CHAR
? "ATA_3WARE_678K" :
457 /* CONTROLLER_3WARE_678K */ "ATA" ),
458 m_escalade_type(escalade_type
), m_disknum(disknum
)
460 set_info().info_name
= strprintf("%s [3ware_disk_%02d]", dev_name
, disknum
);
463 bool freebsd_escalade_device::open()
465 const char *dev
= get_dev_name();
468 if ((fd
= ::open(dev
,O_RDWR
))<0) {
476 int freebsd_escalade_device::ata_command_interface(smart_command_set command
, int select
, char * data
)
478 // to hold true file descriptor
481 // return value and buffer for ioctl()
482 int ioctlreturn
, readdata
=0;
483 struct twe_usercommand
* cmd_twe
= NULL
;
484 TW_OSLI_IOCTL_NO_DATA_BUF
* cmd_twa
= NULL
;
485 TWE_Command_ATA
* ata
= NULL
;
487 // Used by both the SCSI and char interfaces
488 char ioctl_buffer
[TW_IOCTL_BUFFER_SIZE
];
491 printwarning(NO_DISK_3WARE
,NULL
);
495 memset(ioctl_buffer
, 0, TW_IOCTL_BUFFER_SIZE
);
497 if (m_escalade_type
==CONTROLLER_3WARE_9000_CHAR
) {
498 cmd_twa
= (TW_OSLI_IOCTL_NO_DATA_BUF
*)ioctl_buffer
;
499 cmd_twa
->pdata
= ((TW_OSLI_IOCTL_WITH_PAYLOAD
*)cmd_twa
)->payload
.data_buf
;
500 cmd_twa
->driver_pkt
.buffer_length
= 512;
501 ata
= (TWE_Command_ATA
*)&cmd_twa
->cmd_pkt
.command
.cmd_pkt_7k
;
502 } else if (m_escalade_type
==CONTROLLER_3WARE_678K_CHAR
) {
503 cmd_twe
= (struct twe_usercommand
*)ioctl_buffer
;
504 ata
= &cmd_twe
->tu_command
.ata
;
506 pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
507 "Please contact " PACKAGE_BUGREPORT
"\n", m_escalade_type
, m_disknum
);
512 ata
->opcode
= TWE_OP_ATA_PASSTHROUGH
;
514 // Same for (almost) all commands - but some reset below
515 ata
->request_id
= 0xFF;
516 ata
->unit
= m_disknum
;
519 ata
->drive_head
= 0x0;
522 // All SMART commands use this CL/CH signature. These are magic
523 // values from the ATA specifications.
524 ata
->cylinder_lo
= 0x4F;
525 ata
->cylinder_hi
= 0xC2;
527 // SMART ATA COMMAND REGISTER value
528 ata
->command
= ATA_SMART_CMD
;
530 // Is this a command that reads or returns 512 bytes?
531 // passthru->param values are:
532 // 0x0 - non data command without TFR write check,
533 // 0x8 - non data command with TFR write check,
534 // 0xD - data command that returns data to host from device
535 // 0xF - data command that writes data from host to device
536 // passthru->size values are 0x5 for non-data and 0x07 for data
537 if (command
== READ_VALUES
||
538 command
== READ_THRESHOLDS
||
539 command
== READ_LOG
||
540 command
== IDENTIFY
||
541 command
== WRITE_LOG
)
544 if (m_escalade_type
==CONTROLLER_3WARE_678K_CHAR
) {
545 cmd_twe
->tu_data
= data
;
546 cmd_twe
->tu_size
= 512;
548 ata
->sgl_offset
= 0x5;
551 ata
->sector_count
= 0x1;
552 // For 64-bit to work correctly, up the size of the command packet
553 // in dwords by 1 to account for the 64-bit single sgl 'address'
554 // field. Note that this doesn't agree with the typedefs but it's
555 // right (agree with kernel driver behavior/typedefs).
556 //if (sizeof(long)==8)
560 // Non data command -- but doesn't use large sector
561 // count register values.
562 ata
->sgl_offset
= 0x0;
565 ata
->sector_count
= 0x0;
568 // Now set ATA registers depending upon command
570 case CHECK_POWER_MODE
:
571 ata
->command
= ATA_CHECK_POWER_MODE
;
573 ata
->cylinder_lo
= 0;
574 ata
->cylinder_hi
= 0;
577 ata
->features
= ATA_SMART_READ_VALUES
;
579 case READ_THRESHOLDS
:
580 ata
->features
= ATA_SMART_READ_THRESHOLDS
;
583 ata
->features
= ATA_SMART_READ_LOG_SECTOR
;
584 // log number to return
585 ata
->sector_num
= select
;
589 ata
->features
= ATA_SMART_WRITE_LOG_SECTOR
;
590 ata
->sector_count
= 1;
591 ata
->sector_num
= select
;
592 ata
->param
= 0xF; // PIO data write
595 // ATA IDENTIFY DEVICE
596 ata
->command
= ATA_IDENTIFY_DEVICE
;
598 ata
->cylinder_lo
= 0;
599 ata
->cylinder_hi
= 0;
602 // 3WARE controller can NOT have packet device internally
603 pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum
);
607 ata
->features
= ATA_SMART_ENABLE
;
610 ata
->features
= ATA_SMART_DISABLE
;
613 ata
->features
= ATA_SMART_AUTO_OFFLINE
;
614 // Enable or disable?
615 ata
->sector_count
= select
;
618 ata
->features
= ATA_SMART_AUTOSAVE
;
619 // Enable or disable?
620 ata
->sector_count
= select
;
622 case IMMEDIATE_OFFLINE
:
623 ata
->features
= ATA_SMART_IMMEDIATE_OFFLINE
;
624 // What test type to run?
625 ata
->sector_num
= select
;
628 ata
->features
= ATA_SMART_STATUS
;
631 // This is JUST to see if SMART is enabled, by giving SMART status
632 // command. But it doesn't say if status was good, or failing.
633 // See below for the difference.
634 ata
->features
= ATA_SMART_STATUS
;
637 pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
638 "Please contact " PACKAGE_BUGREPORT
"\n", command
, m_disknum
);
643 // Now send the command down through an ioctl()
644 if (m_escalade_type
==CONTROLLER_3WARE_9000_CHAR
) {
645 ioctlreturn
=ioctl(fd
,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH
,cmd_twa
);
647 ioctlreturn
=ioctl(fd
,TWEIO_COMMAND
,cmd_twe
);
650 // Deal with the different error cases
657 // See if the ATA command failed. Now that we have returned from
658 // the ioctl() call, if passthru is valid, then:
659 // - ata->status contains the 3ware controller STATUS
660 // - ata->command contains the ATA STATUS register
661 // - ata->features contains the ATA ERROR register
663 // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
664 // If bit 0 (error bit) is set, then ATA ERROR register is valid.
665 // While we *might* decode the ATA ERROR register, at the moment it
666 // doesn't make much sense: we don't care in detail why the error
669 if (ata
->status
|| (ata
->command
& 0x21)) {
670 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
);
675 // If this is a read data command, copy data to output buffer
677 if (m_escalade_type
==CONTROLLER_3WARE_9000_CHAR
)
678 memcpy(data
, cmd_twa
->pdata
, 512);
681 // For STATUS_CHECK, we need to check register values
682 if (command
==STATUS_CHECK
) {
684 // To find out if the SMART RETURN STATUS is good or failing, we
685 // need to examine the values of the Cylinder Low and Cylinder
688 unsigned short cyl_lo
=ata
->cylinder_lo
;
689 unsigned short cyl_hi
=ata
->cylinder_hi
;
691 // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
692 if (cyl_lo
==0x4F && cyl_hi
==0xC2)
695 // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
696 if (cyl_lo
==0xF4 && cyl_hi
==0x2C)
703 // copy sector count register (one byte!) to return data
704 if (command
==CHECK_POWER_MODE
)
705 *data
=*(char *)&(ata
->sector_count
);
707 // look for nonexistent devices/ports
708 if (command
==IDENTIFY
&& !nonempty(data
, 512)) {
717 /////////////////////////////////////////////////////////////////////////////
718 /// Implement Highpoint RAID support with old functions
720 class freebsd_highpoint_device
721 : public /*implements*/ ata_device_with_command_set
,
722 public /*extends*/ freebsd_smart_device
725 freebsd_highpoint_device(smart_interface
* intf
, const char * dev_name
,
726 unsigned char controller
, unsigned char channel
, unsigned char port
);
729 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
733 unsigned char m_hpt_data
[3]; ///< controller/channel/port
737 freebsd_highpoint_device::freebsd_highpoint_device(smart_interface
* intf
, const char * dev_name
,
738 unsigned char controller
, unsigned char channel
, unsigned char port
)
739 : smart_device(intf
, dev_name
, "hpt", "hpt"),
740 freebsd_smart_device("ATA")
742 m_hpt_data
[0] = controller
; m_hpt_data
[1] = channel
; m_hpt_data
[2] = port
;
743 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]);
746 bool freebsd_highpoint_device::open()
748 const char *dev
= get_dev_name();
751 if ((fd
= ::open(dev
,O_RDWR
))<0) {
759 int freebsd_highpoint_device::ata_command_interface(smart_command_set command
, int select
, char * data
)
763 HPT_IOCTL_PARAM param
;
764 HPT_CHANNEL_INFO_V2 info
;
765 unsigned char* buff
[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER
)];
766 PHPT_PASS_THROUGH_HEADER pide_pt_hdr
, pide_pt_hdr_out
;
768 // get internal deviceid
769 ids
[0] = m_hpt_data
[0] - 1;
770 ids
[1] = m_hpt_data
[1] - 1;
772 memset(¶m
, 0, sizeof(HPT_IOCTL_PARAM
));
774 param
.magic
= HPT_IOCTL_MAGIC
;
775 param
.ctrl_code
= HPT_IOCTL_GET_CHANNEL_INFO_V2
;
776 param
.in
= (unsigned char *)ids
;
777 param
.in_size
= sizeof(unsigned int) * 2;
778 param
.out
= (unsigned char *)&info
;
779 param
.out_size
= sizeof(HPT_CHANNEL_INFO_V2
);
781 if (m_hpt_data
[2]==1) {
782 param
.ctrl_code
= HPT_IOCTL_GET_CHANNEL_INFO
;
783 param
.out_size
= sizeof(HPT_CHANNEL_INFO
);
785 if (ioctl(fd
, HPT_DO_IOCONTROL
, ¶m
)!=0 ||
786 info
.devices
[m_hpt_data
[2]-1]==0) {
790 // perform smart action
791 memset(buff
, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER
));
792 pide_pt_hdr
= (PHPT_PASS_THROUGH_HEADER
)buff
;
794 pide_pt_hdr
->lbamid
= 0x4f;
795 pide_pt_hdr
->lbahigh
= 0xc2;
796 pide_pt_hdr
->command
= ATA_SMART_CMD
;
797 pide_pt_hdr
->id
= info
.devices
[m_hpt_data
[2] - 1];
801 pide_pt_hdr
->feature
=ATA_SMART_READ_VALUES
;
802 pide_pt_hdr
->protocol
=HPT_READ
;
804 case READ_THRESHOLDS
:
805 pide_pt_hdr
->feature
=ATA_SMART_READ_THRESHOLDS
;
806 pide_pt_hdr
->protocol
=HPT_READ
;
809 pide_pt_hdr
->feature
=ATA_SMART_READ_LOG_SECTOR
;
810 pide_pt_hdr
->lbalow
=select
;
811 pide_pt_hdr
->protocol
=HPT_READ
;
814 pide_pt_hdr
->command
=ATA_IDENTIFY_DEVICE
;
815 pide_pt_hdr
->protocol
=HPT_READ
;
818 pide_pt_hdr
->feature
=ATA_SMART_ENABLE
;
821 pide_pt_hdr
->feature
=ATA_SMART_DISABLE
;
824 pide_pt_hdr
->feature
=ATA_SMART_AUTO_OFFLINE
;
825 pide_pt_hdr
->sectorcount
=select
;
828 pide_pt_hdr
->feature
=ATA_SMART_AUTOSAVE
;
829 pide_pt_hdr
->sectorcount
=select
;
831 case IMMEDIATE_OFFLINE
:
832 pide_pt_hdr
->feature
=ATA_SMART_IMMEDIATE_OFFLINE
;
833 pide_pt_hdr
->lbalow
=select
;
837 pide_pt_hdr
->feature
=ATA_SMART_STATUS
;
839 case CHECK_POWER_MODE
:
840 pide_pt_hdr
->command
=ATA_CHECK_POWER_MODE
;
843 memcpy(buff
+sizeof(HPT_PASS_THROUGH_HEADER
), data
, 512);
844 pide_pt_hdr
->feature
=ATA_SMART_WRITE_LOG_SECTOR
;
845 pide_pt_hdr
->lbalow
=select
;
846 pide_pt_hdr
->protocol
=HPT_WRITE
;
849 pout("Unrecognized command %d in highpoint_command_interface()\n"
850 "Please contact " PACKAGE_BUGREPORT
"\n", command
);
854 if (pide_pt_hdr
->protocol
!=0) {
855 pide_pt_hdr
->sectors
= 1;
856 pide_pt_hdr
->sectorcount
= 1;
859 memset(¶m
, 0, sizeof(HPT_IOCTL_PARAM
));
861 param
.magic
= HPT_IOCTL_MAGIC
;
862 param
.ctrl_code
= HPT_IOCTL_IDE_PASS_THROUGH
;
863 param
.in
= (unsigned char *)buff
;
864 param
.in_size
= sizeof(HPT_PASS_THROUGH_HEADER
) + (pide_pt_hdr
->protocol
==HPT_READ
? 0 : pide_pt_hdr
->sectors
* 512);
865 param
.out
= (unsigned char *)buff
+param
.in_size
;
866 param
.out_size
= sizeof(HPT_PASS_THROUGH_HEADER
) + (pide_pt_hdr
->protocol
==HPT_READ
? pide_pt_hdr
->sectors
* 512 : 0);
868 pide_pt_hdr_out
= (PHPT_PASS_THROUGH_HEADER
)param
.out
;
870 if ((ioctl(fd
, HPT_DO_IOCONTROL
, ¶m
)!=0) ||
871 (pide_pt_hdr_out
->command
& 1)) {
875 if (command
==STATUS_CHECK
)
877 unsigned const char normal_lo
=0x4f, normal_hi
=0xc2;
878 unsigned const char failed_lo
=0xf4, failed_hi
=0x2c;
879 unsigned char low
,high
;
881 high
= pide_pt_hdr_out
->lbahigh
;
882 low
= pide_pt_hdr_out
->lbamid
;
884 // Cyl low and Cyl high unchanged means "Good SMART status"
885 if (low
==normal_lo
&& high
==normal_hi
)
888 // These values mean "Bad SMART status"
889 if (low
==failed_lo
&& high
==failed_hi
)
892 // We haven't gotten output that makes sense; print out some debugging info
894 sprintf(buf
,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
895 (int)pide_pt_hdr_out
->command
,
896 (int)pide_pt_hdr_out
->feature
,
897 (int)pide_pt_hdr_out
->sectorcount
,
898 (int)pide_pt_hdr_out
->lbalow
,
899 (int)pide_pt_hdr_out
->lbamid
,
900 (int)pide_pt_hdr_out
->lbahigh
,
901 (int)pide_pt_hdr_out
->sectors
);
902 printwarning(BAD_SMART
,buf
);
904 else if (command
==CHECK_POWER_MODE
)
905 data
[0] = pide_pt_hdr_out
->sectorcount
& 0xff;
906 else if (pide_pt_hdr
->protocol
==HPT_READ
)
907 memcpy(data
, (unsigned char *)buff
+ 2 * sizeof(HPT_PASS_THROUGH_HEADER
),
908 pide_pt_hdr
->sectors
* 512);
913 /////////////////////////////////////////////////////////////////////////////
914 /// Implement standard SCSI support with old functions
916 class freebsd_scsi_device
917 : public /*implements*/ scsi_device
,
918 public /*extends*/ freebsd_smart_device
921 freebsd_scsi_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
923 virtual smart_device
* autodetect_open();
925 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
929 virtual bool close();
933 struct cam_device
*m_camdev
;
936 bool freebsd_scsi_device::open(){
937 const char *dev
= get_dev_name();
939 if ((m_camdev
= cam_open_device(dev
, O_RDWR
)) == NULL
) {
943 set_fd(m_camdev
->fd
);
947 bool freebsd_scsi_device::close(){
948 cam_close_device(m_camdev
);
953 freebsd_scsi_device::freebsd_scsi_device(smart_interface
* intf
,
954 const char * dev_name
, const char * req_type
)
955 : smart_device(intf
, dev_name
, "scsi", req_type
),
956 freebsd_smart_device("SCSI")
961 bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io
* iop
)
963 int report
=scsi_debugmode
;
968 const unsigned char * ucp
= iop
->cmnd
;
971 np
= scsi_get_opcode_name(ucp
[0]);
972 pout(" [%s: ", np
? np
: "<unknown opcode>");
973 for (k
= 0; k
< iop
->cmnd_len
; ++k
)
974 pout("%02x ", ucp
[k
]);
976 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
977 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
979 pout("]\n Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
980 (trunc
? " [only first 256 bytes shown]" : ""));
981 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
988 warnx("error: camdev=0!");
992 if (!(ccb
= cam_getccb(m_camdev
))) {
993 warnx("error allocating ccb");
997 // clear out structure, except for header that was filled in for us
998 bzero(&(&ccb
->ccb_h
)[1],
999 sizeof(struct ccb_scsiio
) - sizeof(struct ccb_hdr
));
1001 cam_fill_csio(&ccb
->csio
,
1004 /* flags */ (iop
->dxfer_dir
== DXFER_NONE
? CAM_DIR_NONE
:(iop
->dxfer_dir
== DXFER_FROM_DEVICE
? CAM_DIR_IN
: CAM_DIR_OUT
)),
1005 /* tagaction */ MSG_SIMPLE_Q_TAG
,
1006 /* dataptr */ iop
->dxferp
,
1007 /* datalen */ iop
->dxfer_len
,
1008 /* senselen */ iop
->max_sense_len
,
1009 /* cdblen */ iop
->cmnd_len
,
1010 /* timout (converted to seconds) */ iop
->timeout
*1000);
1011 memcpy(ccb
->csio
.cdb_io
.cdb_bytes
,iop
->cmnd
,iop
->cmnd_len
);
1013 if (cam_send_ccb(m_camdev
,ccb
) < 0) {
1014 warn("error sending SCSI ccb");
1015 #if (FREEBSDVER > 500000)
1016 cam_error_print(m_camdev
,ccb
,CAM_ESF_ALL
,CAM_EPF_ALL
,stderr
);
1022 if (((ccb
->ccb_h
.status
& CAM_STATUS_MASK
) != CAM_REQ_CMP
) && ((ccb
->ccb_h
.status
& CAM_STATUS_MASK
) != CAM_SCSI_STATUS_ERROR
)) {
1023 #if (FREEBSDVER > 500000)
1024 cam_error_print(m_camdev
,ccb
,CAM_ESF_ALL
,CAM_EPF_ALL
,stderr
);
1031 memcpy(iop
->sensep
,&(ccb
->csio
.sense_data
),sizeof(struct scsi_sense_data
));
1032 iop
->resp_sense_len
= sizeof(struct scsi_sense_data
);
1035 iop
->scsi_status
= ccb
->csio
.scsi_status
;
1042 pout(" status=0\n");
1043 trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
1045 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
1046 (trunc
? " [only first 256 bytes shown]" : ""));
1047 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
1054 /////////////////////////////////////////////////////////////////////////////
1055 /// Implement CCISS RAID support with old functions
1057 class freebsd_cciss_device
1058 : public /*implements*/ scsi_device
,
1059 public /*extends*/ freebsd_smart_device
1062 freebsd_cciss_device(smart_interface
* intf
, const char * name
, unsigned char disknum
);
1064 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
1065 virtual bool open();
1068 unsigned char m_disknum
; ///< Disk number.
1071 bool freebsd_cciss_device::open()
1073 const char *dev
= get_dev_name();
1075 #ifndef HAVE_DEV_CISS_CISSIO_H
1076 pout("CCISS support is not available in this build of smartmontools,\n"
1077 "/usr/src/sys/dev/ciss/cissio.h was not available at build time.\n\n");
1080 if ((fd
= ::open(dev
,O_RDWR
))<0) {
1088 freebsd_cciss_device::freebsd_cciss_device(smart_interface
* intf
,
1089 const char * dev_name
, unsigned char disknum
)
1090 : smart_device(intf
, dev_name
, "cciss", "cciss"),
1091 freebsd_smart_device("SCSI"),
1094 set_info().info_name
= strprintf("%s [cciss_disk_%02d]", dev_name
, disknum
);
1097 bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io
* iop
)
1099 #ifdef HAVE_DEV_CISS_CISSIO_H
1100 int status
= cciss_io_interface(get_fd(), m_disknum
, iop
, scsi_debugmode
);
1102 return set_err(-status
);
1110 /////////////////////////////////////////////////////////////////////////////
1111 /// SCSI open with autodetection support
1113 smart_device
* freebsd_scsi_device::autodetect_open()
1119 // No Autodetection if device type was specified by user
1120 if (*get_req_type())
1123 // The code below is based on smartd.cpp:SCSIFilterKnown()
1126 unsigned char req_buff
[64] = {0, };
1128 if (scsiStdInquiry(this, req_buff
, req_len
)) {
1129 // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
1130 // watch this spot ... other devices could lock up here
1132 if (scsiStdInquiry(this, req_buff
, req_len
)) {
1133 // device doesn't like INQUIRY commands
1135 set_err(EIO
, "INQUIRY failed");
1140 int avail_len
= req_buff
[4] + 5;
1141 int len
= (avail_len
< req_len
? avail_len
: req_len
);
1145 // Use INQUIRY to detect type
1148 if (!memcmp(req_buff
+ 8, "3ware", 5) || !memcmp(req_buff
+ 8, "AMCC", 4)) {
1150 set_err(EINVAL
, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
1151 "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
1157 smart_device
* newdev
= smi()->autodetect_sat_device(this, req_buff
, len
);
1159 // NOTE: 'this' is now owned by '*newdev'
1163 // Nothing special found
1168 /////////////////////////////////////////////////////////////////////////////
1169 /// Implement platform interface with old functions.
1171 class freebsd_smart_interface
1172 : public /*implements*/ smart_interface
1175 virtual std::string
get_os_version_str();
1177 virtual std::string
get_app_examples(const char * appname
);
1179 virtual bool scan_smart_devices(smart_device_list
& devlist
, const char * type
,
1180 const char * pattern
= 0);
1183 virtual ata_device
* get_ata_device(const char * name
, const char * type
);
1185 #if FREEBSDVER > 800100
1186 virtual ata_device
* get_atacam_device(const char * name
, const char * type
);
1189 virtual scsi_device
* get_scsi_device(const char * name
, const char * type
);
1191 virtual smart_device
* autodetect_smart_device(const char * name
);
1193 virtual smart_device
* get_custom_smart_device(const char * name
, const char * type
);
1195 virtual std::string
get_valid_custom_dev_types_str();
1199 //////////////////////////////////////////////////////////////////////
1201 std::string
freebsd_smart_interface::get_os_version_str()
1203 struct utsname osname
;
1205 return strprintf("%s %s %s", osname
.sysname
, osname
.release
, osname
.machine
);
1208 std::string
freebsd_smart_interface::get_app_examples(const char * appname
)
1210 if (!strcmp(appname
, "smartctl"))
1211 return smartctl_examples
;
1215 ata_device
* freebsd_smart_interface::get_ata_device(const char * name
, const char * type
)
1217 return new freebsd_ata_device(this, name
, type
);
1220 #if FREEBSDVER > 800100
1221 ata_device
* freebsd_smart_interface::get_atacam_device(const char * name
, const char * type
)
1223 return new freebsd_atacam_device(this, name
, type
);
1227 scsi_device
* freebsd_smart_interface::get_scsi_device(const char * name
, const char * type
)
1229 return new freebsd_scsi_device(this, name
, type
);
1232 // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
1233 // devices on system despite of it's names
1235 // If any errors occur, leave errno set as it was returned by the
1236 // system call, and return <0.
1239 // names: resulting array
1240 // show_all - export duplicate device name or not
1244 // >=0: number of discovered devices
1246 bool get_dev_names_cam(std::vector
<std::string
> & names
, bool show_all
)
1249 if ((fd
= open(XPT_DEVICE
, O_RDWR
)) == -1) {
1250 if (errno
== ENOENT
) /* There are no CAM device on this computer */
1253 pout("%s control device couldn't opened: %s\n", XPT_DEVICE
, strerror(errno
));
1259 bzero(&ccb
, sizeof(union ccb
));
1261 ccb
.ccb_h
.path_id
= CAM_XPT_PATH_ID
;
1262 ccb
.ccb_h
.target_id
= CAM_TARGET_WILDCARD
;
1263 ccb
.ccb_h
.target_lun
= CAM_LUN_WILDCARD
;
1265 ccb
.ccb_h
.func_code
= XPT_DEV_MATCH
;
1266 int bufsize
= sizeof(struct dev_match_result
) * MAX_NUM_DEV
;
1267 ccb
.cdm
.match_buf_len
= bufsize
;
1268 // TODO: Use local buffer instead of malloc() if possible
1269 ccb
.cdm
.matches
= (struct dev_match_result
*)malloc(bufsize
);
1270 bzero(ccb
.cdm
.matches
,bufsize
); // clear ccb.cdm.matches structure
1272 if (ccb
.cdm
.matches
== NULL
) {
1274 throw std::bad_alloc();
1276 ccb
.cdm
.num_matches
= 0;
1277 ccb
.cdm
.num_patterns
= 0;
1278 ccb
.cdm
.pattern_buf_len
= 0;
1281 * We do the ioctl multiple times if necessary, in case there are
1282 * more than MAX_NUM_DEV nodes in the EDT.
1284 int skip_device
= 0, skip_bus
= 0, changed
= 0; // TODO: bool
1285 std::string devname
;
1287 if (ioctl(fd
, CAMIOCOMMAND
, &ccb
) == -1) {
1289 pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno
));
1290 free(ccb
.cdm
.matches
);
1296 if ((ccb
.ccb_h
.status
!= CAM_REQ_CMP
)
1297 || ((ccb
.cdm
.status
!= CAM_DEV_MATCH_LAST
)
1298 && (ccb
.cdm
.status
!= CAM_DEV_MATCH_MORE
))) {
1299 pout("got CAM error %#x, CDM error %d\n", ccb
.ccb_h
.status
, ccb
.cdm
.status
);
1300 free(ccb
.cdm
.matches
);
1306 for (unsigned i
= 0; i
< ccb
.cdm
.num_matches
; i
++) {
1307 struct bus_match_result
*bus_result
;
1308 struct device_match_result
*dev_result
;
1309 struct periph_match_result
*periph_result
;
1311 if (ccb
.cdm
.matches
[i
].type
== DEV_MATCH_BUS
) {
1312 bus_result
= &ccb
.cdm
.matches
[i
].result
.bus_result
;
1314 if (strcmp(bus_result
->dev_name
,"ata") == 0 /* ATAPICAM devices will be probed as ATA devices, skip'em there */
1315 || strcmp(bus_result
->dev_name
,"xpt") == 0) /* skip XPT bus at all */
1320 } else if (ccb
.cdm
.matches
[i
].type
== DEV_MATCH_DEVICE
) {
1321 dev_result
= &ccb
.cdm
.matches
[i
].result
.device_result
;
1323 if (dev_result
->flags
& DEV_RESULT_UNCONFIGURED
|| skip_bus
== 1)
1328 // /* Shall we skip non T_DIRECT devices ? */
1329 // if (dev_result->inq_data.device != T_DIRECT)
1332 } else if (ccb
.cdm
.matches
[i
].type
== DEV_MATCH_PERIPH
&&
1333 (skip_device
== 0 || show_all
)) {
1334 /* One device may be populated as many peripherals (pass0 & da0 for example).
1335 * We are searching for latest name
1337 periph_result
= &ccb
.cdm
.matches
[i
].result
.periph_result
;
1338 devname
= strprintf("%s%s%d", _PATH_DEV
, periph_result
->periph_name
, periph_result
->unit_number
);
1341 if ((changed
== 1 || show_all
) && !devname
.empty()) {
1342 names
.push_back(devname
);
1348 } while ((ccb
.ccb_h
.status
== CAM_REQ_CMP
) && (ccb
.cdm
.status
== CAM_DEV_MATCH_MORE
));
1350 if (!devname
.empty())
1351 names
.push_back(devname
);
1353 free(ccb
.cdm
.matches
);
1358 // we are using ATA subsystem enumerator to found all ATA devices on system
1359 // despite of it's names
1361 // If any errors occur, leave errno set as it was returned by the
1362 // system call, and return <0.
1366 // >=0: number of discovered devices
1367 int get_dev_names_ata(char*** names
) {
1368 struct ata_ioc_devices devices
;
1369 int fd
=-1,maxchannel
,serrno
=-1,n
=0;
1374 if ((fd
= open(ATA_DEVICE
, O_RDWR
)) < 0) {
1375 if (errno
== ENOENT
) /* There are no ATA device on this computer */
1378 pout("%s control device can't be opened: %s\n", ATA_DEVICE
, strerror(errno
));
1383 if (ioctl(fd
, IOCATAGMAXCHANNEL
, &maxchannel
) < 0) {
1385 pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno
));
1390 // allocate space for up to MAX_NUM_DEV number of ATA devices
1391 mp
= (char **)calloc(MAX_NUM_DEV
, sizeof(char*));
1394 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__
);
1399 for (devices
.channel
= 0; devices
.channel
< maxchannel
&& n
< MAX_NUM_DEV
; devices
.channel
++) {
1402 if (ioctl(fd
, IOCATADEVICES
, &devices
) < 0) {
1404 continue; /* such channel not exist */
1405 pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE
, devices
.channel
, strerror(errno
));
1409 for (j
=0;j
<=1 && n
<MAX_NUM_DEV
;j
++) {
1410 if (devices
.name
[j
][0] != '\0') {
1411 asprintf(mp
+n
, "%s%s", _PATH_DEV
, devices
.name
[j
]);
1412 if (mp
[n
] == NULL
) {
1413 pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__
);
1417 bytes
+=1+strlen(mp
[n
]);
1422 mp
= (char **)reallocf(mp
,n
*(sizeof (char*))); // shrink to correct size
1423 if (mp
== NULL
&& n
> 0 ) { // reallocf never fail for size=0, but may return NULL
1425 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__
);
1429 bytes
+= (n
)*(sizeof(char*)); // and set allocated byte count
1448 bool freebsd_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
1449 const char * type
, const char * pattern
/*= 0*/)
1452 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
1457 char * * atanames
= 0; int numata
= 0;
1458 if (!type
|| !strcmp(type
, "ata")) {
1459 numata
= get_dev_names_ata(&atanames
);
1466 std::vector
<std::string
> scsinames
;
1467 if (!type
|| !strcmp(type
, "scsi")) { // do not export duplicated names
1468 if (!get_dev_names_cam(scsinames
, false)) {
1478 for (i
= 0; i
< numata
; i
++) {
1479 ata_device
* atadev
= get_ata_device(atanames
[i
], type
);
1481 devlist
.push_back(atadev
);
1484 if(numata
) free(atanames
);
1486 for (i
= 0; i
< (int)scsinames
.size(); i
++) {
1487 if(!*type
) { // try USB autodetection if no type specified
1488 smart_device
* smartdev
= autodetect_smart_device(scsinames
[i
].c_str());
1490 devlist
.push_back(smartdev
);
1493 scsi_device
* scsidev
= get_scsi_device(scsinames
[i
].c_str(), type
);
1495 devlist
.push_back(scsidev
);
1502 #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
1503 static char done
[USB_MAX_DEVICES
];
1505 static int usbdevinfo(int f
, int a
, int rec
, int busno
, unsigned short & vendor_id
,
1506 unsigned short & product_id
, unsigned short & version
)
1509 struct usb_device_info di
;
1513 snprintf(devname
, sizeof(devname
),"umass%d",busno
);
1516 e
= ioctl(f
, USB_DEVICEINFO
, &di
);
1519 printf("addr %d: I/O error\n", a
);
1525 for (i
= 0; i
< USB_MAX_DEVNAMES
; i
++) {
1526 if (di
.udi_devnames
[i
][0]) {
1527 if(strcmp(di
.udi_devnames
[i
],devname
)==0) {
1529 vendor_id
= di
.udi_vendorNo
;
1530 product_id
= di
.udi_productNo
;
1531 version
= di
.udi_releaseNo
;
1539 for (p
= 0; p
< di
.udi_nports
; p
++) {
1540 int s
= di
.udi_ports
[p
];
1541 if (s
>= USB_MAX_DEVICES
) {
1545 printf("addr 0 should never happen!\n");
1547 if(usbdevinfo(f
, s
, 1, busno
, vendor_id
, product_id
, version
)) return 1;
1555 static int usbdevlist(int busno
,unsigned short & vendor_id
,
1556 unsigned short & product_id
, unsigned short & version
)
1558 #if (FREEBSDVER >= 800000) // libusb2 interface
1559 struct libusb20_device
*pdev
= NULL
;
1560 struct libusb20_backend
*pbe
;
1561 uint32_t matches
= 0;
1562 char buf
[128]; // do not change!
1565 struct LIBUSB20_DEVICE_DESC_DECODED
*pdesc
;
1567 pbe
= libusb20_be_alloc_default();
1569 while ((pdev
= libusb20_be_device_foreach(pbe
, pdev
))) {
1572 if (libusb20_dev_open(pdev
, 0)) {
1573 warnx("libusb20_dev_open: could not open device");
1577 pdesc
=libusb20_dev_get_device_desc(pdev
);
1579 snprintf(devname
, sizeof(devname
),"umass%d:",busno
);
1580 for (n
= 0; n
!= 255; n
++) {
1581 if (libusb20_dev_get_iface_desc(pdev
, n
, buf
, sizeof(buf
)))
1585 if(strncmp(buf
,devname
,strlen(devname
))==0){
1587 vendor_id
= pdesc
->idVendor
;
1588 product_id
= pdesc
->idProduct
;
1589 version
= pdesc
->bcdDevice
;
1590 libusb20_dev_close(pdev
);
1591 libusb20_be_free(pbe
);
1596 libusb20_dev_close(pdev
);
1600 printf("No device match or lack of permissions.\n");
1603 libusb20_be_free(pbe
);
1606 #else // freebsd < 8.0 USB stack, ioctl interface
1612 for (ncont
= 0, i
= 0; i
< 10; i
++) {
1613 snprintf(buf
, sizeof(buf
), "%s%d", USBDEV
, i
);
1614 f
= open(buf
, O_RDONLY
);
1616 memset(done
, 0, sizeof done
);
1617 for (a
= 1; a
< USB_MAX_DEVICES
; a
++) {
1619 rc
= usbdevinfo(f
, a
, 1, busno
,vendor_id
, product_id
, version
);
1626 if (errno
== ENOENT
|| errno
== ENXIO
)
1636 smart_device
* freebsd_smart_interface::autodetect_smart_device(const char * name
)
1638 unsigned short vendor_id
= 0, product_id
= 0, version
= 0;
1639 struct cam_device
*cam_dev
;
1645 // if dev_name null, or string length zero
1646 if (!name
|| !(len
= strlen(name
)))
1650 char * * atanames
= 0; int numata
= 0;
1651 numata
= get_dev_names_ata(&atanames
);
1653 // check ATA/ATAPI devices
1654 for (i
= 0; i
< numata
; i
++) {
1655 if(!strcmp(atanames
[i
],name
)) {
1656 for (c
= i
; c
< numata
; c
++) free(atanames
[c
]);
1658 return new freebsd_ata_device(this, name
, "");
1660 else free(atanames
[i
]);
1662 if(numata
) free(atanames
);
1666 pout("Unable to get ATA device list\n");
1670 std::vector
<std::string
> scsinames
;
1671 if (!get_dev_names_cam(scsinames
, true))
1672 pout("Unable to get CAM device list\n");
1673 else if (!scsinames
.empty()) {
1674 // check all devices on CAM bus
1675 for (i
= 0; i
< (int)scsinames
.size(); i
++) {
1676 if(strcmp(scsinames
[i
].c_str(), name
)==0)
1677 { // our disk device is CAM
1678 if ((cam_dev
= cam_open_device(name
, O_RDWR
)) == NULL
) {
1685 bzero(&(&ccb
.ccb_h
)[1], PATHINQ_SETTINGS_SIZE
);
1686 ccb
.ccb_h
.func_code
= XPT_PATH_INQ
; // send PATH_INQ to the device
1687 if (ioctl(cam_dev
->fd
, CAMIOCOMMAND
, &ccb
) == -1) {
1688 warn("Get Transfer Settings CCB failed\n"
1689 "%s", strerror(errno
));
1690 cam_close_device(cam_dev
);
1693 // now check if we are working with USB device, see umass.c
1694 if(strcmp(ccb
.cpi
.dev_name
,"umass-sim") == 0) { // USB device found
1695 usbdevlist(bus
,vendor_id
, product_id
, version
);
1696 int bus
=ccb
.cpi
.unit_number
; // unit_number will match umass number
1697 cam_close_device(cam_dev
);
1698 if(usbdevlist(bus
,vendor_id
, product_id
, version
)){
1699 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
, version
);
1701 return get_sat_device(usbtype
, new freebsd_scsi_device(this, name
, ""));
1705 #if FREEBSDVER > 800100
1706 // check if we have ATA device connected to CAM (ada)
1707 if(ccb
.cpi
.protocol
== PROTO_ATA
){
1708 cam_close_device(cam_dev
);
1709 return new freebsd_atacam_device(this, name
, "");
1712 // close cam device, we don`t need it anymore
1713 cam_close_device(cam_dev
);
1714 // handle as usual scsi
1715 return new freebsd_scsi_device(this, name
, "");
1719 // device type unknown
1724 smart_device
* freebsd_smart_interface::get_custom_smart_device(const char * name
, const char * type
)
1727 static const char * fbsd_dev_twe_ctrl
= "/dev/twe";
1728 static const char * fbsd_dev_twa_ctrl
= "/dev/twa";
1729 int disknum
= -1, n1
= -1, n2
= -1, contr
= -1;
1731 if (sscanf(type
, "3ware,%n%d%n", &n1
, &disknum
, &n2
) == 1 || n1
== 6) {
1732 if (n2
!= (int)strlen(type
)) {
1733 set_err(EINVAL
, "Option -d 3ware,N requires N to be a non-negative integer");
1736 if (!(0 <= disknum
&& disknum
<= 127)) {
1737 set_err(EINVAL
, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum
);
1741 // guess 3ware device type based on device name
1742 if (!strncmp(fbsd_dev_twa_ctrl
, name
, strlen(fbsd_dev_twa_ctrl
))){
1743 contr
=CONTROLLER_3WARE_9000_CHAR
;
1745 if (!strncmp(fbsd_dev_twe_ctrl
, name
, strlen(fbsd_dev_twe_ctrl
))){
1746 contr
=CONTROLLER_3WARE_678K_CHAR
;
1750 set_err(EINVAL
, "3ware controller type unknown, use %sX or %sX devices",
1751 fbsd_dev_twe_ctrl
, fbsd_dev_twa_ctrl
);
1754 return new freebsd_escalade_device(this, name
, contr
, disknum
);
1758 int controller
= -1, channel
= -1; disknum
= 1;
1759 n1
= n2
= -1; int n3
= -1;
1760 if (sscanf(type
, "hpt,%n%d/%d%n/%d%n", &n1
, &controller
, &channel
, &n2
, &disknum
, &n3
) >= 2 || n1
== 4) {
1761 int len
= strlen(type
);
1762 if (!(n2
== len
|| n3
== len
)) {
1763 set_err(EINVAL
, "Option '-d hpt,L/M/N' supports 2-3 items");
1766 if (!(1 <= controller
&& controller
<= 8)) {
1767 set_err(EINVAL
, "Option '-d hpt,L/M/N' invalid controller id L supplied");
1770 if (!(1 <= channel
&& channel
<= 8)) {
1771 set_err(EINVAL
, "Option '-d hpt,L/M/N' invalid channel number M supplied");
1774 if (!(1 <= disknum
&& disknum
<= 15)) {
1775 set_err(EINVAL
, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
1778 return new freebsd_highpoint_device(this, name
, controller
, channel
, disknum
);
1782 disknum
= n1
= n2
= -1;
1783 if (sscanf(type
, "cciss,%n%d%n", &n1
, &disknum
, &n2
) == 1 || n1
== 6) {
1784 if (n2
!= (int)strlen(type
)) {
1785 set_err(EINVAL
, "Option -d cciss,N requires N to be a non-negative integer");
1788 if (!(0 <= disknum
&& disknum
<= 127)) {
1789 set_err(EINVAL
, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum
);
1792 return new freebsd_cciss_device(this, name
, disknum
);
1794 #if FREEBSDVER > 800100
1796 if(!strcmp(type
,"atacam"))
1797 return new freebsd_atacam_device(this, name
, "");
1803 std::string
freebsd_smart_interface::get_valid_custom_dev_types_str()
1805 return "3ware,N, hpt,L/M/N, cciss,N"
1806 #if FREEBSDVER > 800100
1814 /////////////////////////////////////////////////////////////////////////////
1815 /// Initialize platform interface and register with smi()
1817 void smart_interface::init()
1819 static os_freebsd::freebsd_smart_interface the_interface
;
1820 smart_interface::set(&the_interface
);