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>
24 #include <cam/scsi/scsi_message.h>
25 #include <cam/scsi/scsi_pass.h>
26 #if defined(__DragonFly__)
36 #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>
63 #include <dev/usb/usb.h>
64 #include <dev/usb/usbhid.h>
67 #define CONTROLLER_3WARE_9000_CHAR 0x01
68 #define CONTROLLER_3WARE_678K_CHAR 0x02
70 #ifndef PATHINQ_SETTINGS_SIZE
71 #define PATHINQ_SETTINGS_SIZE 128
74 static __unused
const char *filenameandversion
="$Id: os_freebsd.cpp 3037 2010-01-16 20:07:13Z chrfranke $";
76 const char *os_XXXX_c_cvsid
="$Id: os_freebsd.cpp 3037 2010-01-16 20:07:13Z chrfranke $" \
77 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
79 extern smartmonctrl
* con
;
83 #define NO_DISK_3WARE 2
87 // Utility function for printing warnings
88 void printwarning(int msgNo
, const char* extra
) {
89 static int printed
[] = {0,0,0,0};
90 static const char* message
[]={
91 "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n",
93 "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE
"\nRegister values returned from SMART Status command are:\n",
95 "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
97 "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
100 if (msgNo
>= 0 && msgNo
<= MAX_MSG
) {
101 if (!printed
[msgNo
]) {
103 pout("%s", message
[msgNo
]);
111 // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
113 #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
114 #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
115 #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
118 #define ATA_DEVICE "/dev/ata"
121 // global variable holding byte count of allocated memory
124 const char * dev_freebsd_cpp_cvsid
= "$Id: os_freebsd.cpp 3037 2010-01-16 20:07:13Z chrfranke $"
125 DEV_INTERFACE_H_CVSID
;
127 extern smartmonctrl
* con
; // con->reportscsiioctl
129 /////////////////////////////////////////////////////////////////////////////
131 namespace os_freebsd
{ // No need to publish anything, name provided for Doxygen
133 /////////////////////////////////////////////////////////////////////////////
134 /// Implement shared open/close routines with old functions.
136 class freebsd_smart_device
137 : virtual public /*implements*/ smart_device
140 explicit freebsd_smart_device(const char * mode
)
141 : smart_device(never_called
),
142 m_fd(-1), m_mode(mode
) { }
144 virtual ~freebsd_smart_device() throw();
146 virtual bool is_open() const;
150 virtual bool close();
153 /// Return filedesc for derived classes.
161 int m_fd
; ///< filedesc, -1 if not open.
162 const char * m_mode
; ///< Mode string for deviceopen().
166 static inline void * reallocf(void *ptr
, size_t size
) {
167 void *rv
= realloc(ptr
, size
);
168 if((rv
== NULL
) && (size
!= 0))
174 freebsd_smart_device::~freebsd_smart_device() throw()
177 os_freebsd::freebsd_smart_device::close();
180 // migration from the old_style
181 unsigned char m_controller_type
;
182 unsigned char m_controller_port
;
184 // examples for smartctl
185 static const char smartctl_examples
[] =
186 "=================================================== SMARTCTL EXAMPLES =====\n\n"
187 " smartctl -a /dev/ad0 (Prints all SMART information)\n\n"
188 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
189 " (Enables SMART on first disk)\n\n"
190 " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n\n"
191 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
192 " (Prints Self-Test & Attribute errors)\n"
193 " (Prints Self-Test & Attribute errors)\n\n"
194 " smartctl -a --device=3ware,2 /dev/twa0\n"
195 " smartctl -a --device=3ware,2 /dev/twe0\n"
196 " (Prints all SMART information for ATA disk on\n"
197 " third port of first 3ware RAID controller)\n"
198 " smartctl -a --device=cciss,0 /dev/ciss0\n"
199 " (Prints all SMART information for first disk \n"
200 " on Common Interface for SCSI-3 Support driver)\n"
204 bool freebsd_smart_device::is_open() const
210 bool freebsd_smart_device::open()
212 const char *dev
= get_dev_name();
213 if ((m_fd
= ::open(dev
,O_RDONLY
))<0) {
220 bool freebsd_smart_device::close()
223 // close device, if open
225 failed
=::close(get_fd());
229 if(failed
) return false;
233 /////////////////////////////////////////////////////////////////////////////
234 /// Implement standard ATA support
236 class freebsd_ata_device
237 : public /*implements*/ ata_device
,
238 public /*extends*/ freebsd_smart_device
241 freebsd_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
242 virtual bool ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
);
245 virtual int do_cmd(struct ata_ioc_request
* request
);
248 freebsd_ata_device::freebsd_ata_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
249 : smart_device(intf
, dev_name
, "ata", req_type
),
250 freebsd_smart_device("ATA")
254 int freebsd_ata_device::do_cmd( struct ata_ioc_request
* request
)
257 return ioctl(fd
, IOCATAREQUEST
, request
);
262 bool freebsd_ata_device::ata_pass_through(const ata_cmd_in
& in
, ata_cmd_out
& out
)
264 if (!ata_cmd_is_ok(in
, true, true, true)) // data_out_support
267 struct ata_ioc_request request
;
268 bzero(&request
,sizeof(struct ata_ioc_request
));
270 request
.timeout
=SCSI_TIMEOUT_DEFAULT
;
271 request
.u
.ata
.command
=in
.in_regs
.command
;
272 request
.u
.ata
.feature
=in
.in_regs
.features
;
274 request
.u
.ata
.count
= in
.in_regs
.sector_count_16
;
275 request
.u
.ata
.lba
= in
.in_regs
.lba_48
;
277 switch (in
.direction
) {
278 case ata_cmd_in::no_data
:
279 request
.flags
=ATA_CMD_CONTROL
;
281 case ata_cmd_in::data_in
:
282 request
.flags
=ATA_CMD_READ
;
283 request
.data
=(char *)in
.buffer
;
284 request
.count
=in
.size
;
286 case ata_cmd_in::data_out
:
287 request
.flags
=ATA_CMD_WRITE
;
288 request
.data
=(char *)in
.buffer
;
289 request
.count
=in
.size
;
292 return set_err(ENOSYS
);
297 if (do_cmd(&request
))
298 return set_err(errno
);
300 return set_err(EIO
, "request failed, error code 0x%02x", request
.error
);
302 out
.out_regs
.error
= request
.error
;
303 out
.out_regs
.sector_count_16
= request
.u
.ata
.count
;
304 out
.out_regs
.lba_48
= request
.u
.ata
.lba
;
307 // Command specific processing
308 if (in
.in_regs
.command
== ATA_SMART_CMD
309 && in
.in_regs
.features
== ATA_SMART_STATUS
310 && in
.out_needed
.lba_high
)
312 unsigned const char normal_lo
=0x4f, normal_hi
=0xc2;
313 unsigned const char failed_lo
=0xf4, failed_hi
=0x2c;
315 #if (FREEBSDVER < 502000)
316 printwarning(NO_RETURN
,NULL
);
319 // Cyl low and Cyl high unchanged means "Good SMART status"
320 if (!(out
.out_regs
.lba_mid
==normal_lo
&& out
.out_regs
.lba_high
==normal_hi
)
321 // These values mean "Bad SMART status"
322 && !(out
.out_regs
.lba_mid
==failed_lo
&& out
.out_regs
.lba_high
==failed_hi
))
325 // We haven't gotten output that makes sense; print out some debugging info
327 sprintf(buf
,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
328 (int)request
.u
.ata
.command
,
329 (int)request
.u
.ata
.feature
,
330 (int)request
.u
.ata
.count
,
331 (int)((request
.u
.ata
.lba
) & 0xff),
332 (int)((request
.u
.ata
.lba
>>8) & 0xff),
333 (int)((request
.u
.ata
.lba
>>16) & 0xff),
335 printwarning(BAD_SMART
,buf
);
336 out
.out_regs
.lba_high
= failed_hi
;
337 out
.out_regs
.lba_mid
= failed_lo
;
344 #if FREEBSDVER > 800100
345 class freebsd_atacam_device
: public freebsd_ata_device
348 freebsd_atacam_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
)
349 : smart_device(intf
, dev_name
, "atacam", req_type
), freebsd_ata_device(intf
, dev_name
, req_type
)
353 virtual bool close();
357 struct cam_device
*m_camdev
;
359 virtual int do_cmd( struct ata_ioc_request
* request
);
362 bool freebsd_atacam_device::open(){
363 const char *dev
= get_dev_name();
365 if ((m_camdev
= cam_open_device(dev
, O_RDWR
)) == NULL
) {
369 set_fd(m_camdev
->fd
);
373 bool freebsd_atacam_device::close(){
374 cam_close_device(m_camdev
);
379 int freebsd_atacam_device::do_cmd( struct ata_ioc_request
* request
)
384 memset(&ccb
, 0, sizeof(ccb
));
386 if (request
->count
== 0)
387 camflags
= CAM_DIR_NONE
;
388 else if (request
->flags
== ATA_CMD_READ
)
389 camflags
= CAM_DIR_IN
;
391 camflags
= CAM_DIR_OUT
;
393 cam_fill_ataio(&ccb
.ataio
,
398 (u_int8_t
*)request
->data
,
400 request
->timeout
* 1000); // timeout in seconds
403 ccb
.ataio
.cmd
.flags
= 0;
404 ccb
.ataio
.cmd
.command
= request
->u
.ata
.command
;
405 ccb
.ataio
.cmd
.features
= request
->u
.ata
.feature
;
406 ccb
.ataio
.cmd
.lba_low
= request
->u
.ata
.lba
;
407 ccb
.ataio
.cmd
.lba_mid
= request
->u
.ata
.lba
>> 8;
408 ccb
.ataio
.cmd
.lba_high
= request
->u
.ata
.lba
>> 16;
409 ccb
.ataio
.cmd
.device
= 0x40 | ((request
->u
.ata
.lba
>> 24) & 0x0f);
410 ccb
.ataio
.cmd
.sector_count
= request
->u
.ata
.count
;
412 ccb
.ccb_h
.flags
|= CAM_DEV_QFRZDIS
;
414 if (cam_send_ccb(m_camdev
, &ccb
) < 0) {
415 err(1, "cam_send_ccb");
419 if ((ccb
.ccb_h
.status
& CAM_STATUS_MASK
) == CAM_REQ_CMP
)
422 cam_error_print(m_camdev
, &ccb
, CAM_ESF_ALL
, CAM_EPF_ALL
, stderr
);
428 /////////////////////////////////////////////////////////////////////////////
429 /// Implement AMCC/3ware RAID support with old functions
431 class freebsd_escalade_device
432 : public /*implements*/ ata_device_with_command_set
,
433 public /*extends*/ freebsd_smart_device
436 freebsd_escalade_device(smart_interface
* intf
, const char * dev_name
,
437 int escalade_type
, int disknum
);
440 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
444 int m_escalade_type
; ///< Type string for escalade_command_interface().
445 int m_disknum
; ///< Disk number.
448 freebsd_escalade_device::freebsd_escalade_device(smart_interface
* intf
, const char * dev_name
,
449 int escalade_type
, int disknum
)
450 : smart_device(intf
, dev_name
, "3ware", "3ware"),
451 freebsd_smart_device(
452 escalade_type
==CONTROLLER_3WARE_9000_CHAR
? "ATA_3WARE_9000" :
453 escalade_type
==CONTROLLER_3WARE_678K_CHAR
? "ATA_3WARE_678K" :
454 /* CONTROLLER_3WARE_678K */ "ATA" ),
455 m_escalade_type(escalade_type
), m_disknum(disknum
)
457 set_info().info_name
= strprintf("%s [3ware_disk_%02d]", dev_name
, disknum
);
460 bool freebsd_escalade_device::open()
462 const char *dev
= get_dev_name();
465 if ((fd
= ::open(dev
,O_RDWR
))<0) {
473 int freebsd_escalade_device::ata_command_interface(smart_command_set command
, int select
, char * data
)
475 // to hold true file descriptor
478 // return value and buffer for ioctl()
479 int ioctlreturn
, readdata
=0;
480 struct twe_usercommand
* cmd_twe
= NULL
;
481 TW_OSLI_IOCTL_NO_DATA_BUF
* cmd_twa
= NULL
;
482 TWE_Command_ATA
* ata
= NULL
;
484 // Used by both the SCSI and char interfaces
485 char ioctl_buffer
[TW_IOCTL_BUFFER_SIZE
];
488 printwarning(NO_DISK_3WARE
,NULL
);
492 memset(ioctl_buffer
, 0, TW_IOCTL_BUFFER_SIZE
);
494 if (m_escalade_type
==CONTROLLER_3WARE_9000_CHAR
) {
495 cmd_twa
= (TW_OSLI_IOCTL_NO_DATA_BUF
*)ioctl_buffer
;
496 cmd_twa
->pdata
= ((TW_OSLI_IOCTL_WITH_PAYLOAD
*)cmd_twa
)->payload
.data_buf
;
497 cmd_twa
->driver_pkt
.buffer_length
= 512;
498 ata
= (TWE_Command_ATA
*)&cmd_twa
->cmd_pkt
.command
.cmd_pkt_7k
;
499 } else if (m_escalade_type
==CONTROLLER_3WARE_678K_CHAR
) {
500 cmd_twe
= (struct twe_usercommand
*)ioctl_buffer
;
501 ata
= &cmd_twe
->tu_command
.ata
;
503 pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
504 "Please contact " PACKAGE_BUGREPORT
"\n", m_escalade_type
, m_disknum
);
509 ata
->opcode
= TWE_OP_ATA_PASSTHROUGH
;
511 // Same for (almost) all commands - but some reset below
512 ata
->request_id
= 0xFF;
513 ata
->unit
= m_disknum
;
516 ata
->drive_head
= 0x0;
519 // All SMART commands use this CL/CH signature. These are magic
520 // values from the ATA specifications.
521 ata
->cylinder_lo
= 0x4F;
522 ata
->cylinder_hi
= 0xC2;
524 // SMART ATA COMMAND REGISTER value
525 ata
->command
= ATA_SMART_CMD
;
527 // Is this a command that reads or returns 512 bytes?
528 // passthru->param values are:
529 // 0x0 - non data command without TFR write check,
530 // 0x8 - non data command with TFR write check,
531 // 0xD - data command that returns data to host from device
532 // 0xF - data command that writes data from host to device
533 // passthru->size values are 0x5 for non-data and 0x07 for data
534 if (command
== READ_VALUES
||
535 command
== READ_THRESHOLDS
||
536 command
== READ_LOG
||
537 command
== IDENTIFY
||
538 command
== WRITE_LOG
)
541 if (m_escalade_type
==CONTROLLER_3WARE_678K_CHAR
) {
542 cmd_twe
->tu_data
= data
;
543 cmd_twe
->tu_size
= 512;
545 ata
->sgl_offset
= 0x5;
548 ata
->sector_count
= 0x1;
549 // For 64-bit to work correctly, up the size of the command packet
550 // in dwords by 1 to account for the 64-bit single sgl 'address'
551 // field. Note that this doesn't agree with the typedefs but it's
552 // right (agree with kernel driver behavior/typedefs).
553 //if (sizeof(long)==8)
557 // Non data command -- but doesn't use large sector
558 // count register values.
559 ata
->sgl_offset
= 0x0;
562 ata
->sector_count
= 0x0;
565 // Now set ATA registers depending upon command
567 case CHECK_POWER_MODE
:
568 ata
->command
= ATA_CHECK_POWER_MODE
;
570 ata
->cylinder_lo
= 0;
571 ata
->cylinder_hi
= 0;
574 ata
->features
= ATA_SMART_READ_VALUES
;
576 case READ_THRESHOLDS
:
577 ata
->features
= ATA_SMART_READ_THRESHOLDS
;
580 ata
->features
= ATA_SMART_READ_LOG_SECTOR
;
581 // log number to return
582 ata
->sector_num
= select
;
586 ata
->features
= ATA_SMART_WRITE_LOG_SECTOR
;
587 ata
->sector_count
= 1;
588 ata
->sector_num
= select
;
589 ata
->param
= 0xF; // PIO data write
592 // ATA IDENTIFY DEVICE
593 ata
->command
= ATA_IDENTIFY_DEVICE
;
595 ata
->cylinder_lo
= 0;
596 ata
->cylinder_hi
= 0;
599 // 3WARE controller can NOT have packet device internally
600 pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum
);
604 ata
->features
= ATA_SMART_ENABLE
;
607 ata
->features
= ATA_SMART_DISABLE
;
610 ata
->features
= ATA_SMART_AUTO_OFFLINE
;
611 // Enable or disable?
612 ata
->sector_count
= select
;
615 ata
->features
= ATA_SMART_AUTOSAVE
;
616 // Enable or disable?
617 ata
->sector_count
= select
;
619 case IMMEDIATE_OFFLINE
:
620 ata
->features
= ATA_SMART_IMMEDIATE_OFFLINE
;
621 // What test type to run?
622 ata
->sector_num
= select
;
625 ata
->features
= ATA_SMART_STATUS
;
628 // This is JUST to see if SMART is enabled, by giving SMART status
629 // command. But it doesn't say if status was good, or failing.
630 // See below for the difference.
631 ata
->features
= ATA_SMART_STATUS
;
634 pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
635 "Please contact " PACKAGE_BUGREPORT
"\n", command
, m_disknum
);
640 // Now send the command down through an ioctl()
641 if (m_escalade_type
==CONTROLLER_3WARE_9000_CHAR
) {
642 ioctlreturn
=ioctl(fd
,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH
,cmd_twa
);
644 ioctlreturn
=ioctl(fd
,TWEIO_COMMAND
,cmd_twe
);
647 // Deal with the different error cases
654 // See if the ATA command failed. Now that we have returned from
655 // the ioctl() call, if passthru is valid, then:
656 // - ata->status contains the 3ware controller STATUS
657 // - ata->command contains the ATA STATUS register
658 // - ata->features contains the ATA ERROR register
660 // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
661 // If bit 0 (error bit) is set, then ATA ERROR register is valid.
662 // While we *might* decode the ATA ERROR register, at the moment it
663 // doesn't make much sense: we don't care in detail why the error
666 if (ata
->status
|| (ata
->command
& 0x21)) {
667 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
);
672 // If this is a read data command, copy data to output buffer
674 if (m_escalade_type
==CONTROLLER_3WARE_9000_CHAR
)
675 memcpy(data
, cmd_twa
->pdata
, 512);
678 // For STATUS_CHECK, we need to check register values
679 if (command
==STATUS_CHECK
) {
681 // To find out if the SMART RETURN STATUS is good or failing, we
682 // need to examine the values of the Cylinder Low and Cylinder
685 unsigned short cyl_lo
=ata
->cylinder_lo
;
686 unsigned short cyl_hi
=ata
->cylinder_hi
;
688 // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
689 if (cyl_lo
==0x4F && cyl_hi
==0xC2)
692 // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
693 if (cyl_lo
==0xF4 && cyl_hi
==0x2C)
700 // copy sector count register (one byte!) to return data
701 if (command
==CHECK_POWER_MODE
)
702 *data
=*(char *)&(ata
->sector_count
);
704 // look for nonexistent devices/ports
705 if (command
==IDENTIFY
&& !nonempty(data
, 512)) {
714 /////////////////////////////////////////////////////////////////////////////
715 /// Implement Highpoint RAID support with old functions
717 class freebsd_highpoint_device
718 : public /*implements*/ ata_device_with_command_set
,
719 public /*extends*/ freebsd_smart_device
722 freebsd_highpoint_device(smart_interface
* intf
, const char * dev_name
,
723 unsigned char controller
, unsigned char channel
, unsigned char port
);
726 virtual int ata_command_interface(smart_command_set command
, int select
, char * data
);
730 unsigned char m_hpt_data
[3]; ///< controller/channel/port
734 freebsd_highpoint_device::freebsd_highpoint_device(smart_interface
* intf
, const char * dev_name
,
735 unsigned char controller
, unsigned char channel
, unsigned char port
)
736 : smart_device(intf
, dev_name
, "hpt", "hpt"),
737 freebsd_smart_device("ATA")
739 m_hpt_data
[0] = controller
; m_hpt_data
[1] = channel
; m_hpt_data
[2] = port
;
740 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]);
743 bool freebsd_highpoint_device::open()
745 const char *dev
= get_dev_name();
748 if ((fd
= ::open(dev
,O_RDWR
))<0) {
756 int freebsd_highpoint_device::ata_command_interface(smart_command_set command
, int select
, char * data
)
760 HPT_IOCTL_PARAM param
;
761 HPT_CHANNEL_INFO_V2 info
;
762 unsigned char* buff
[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER
)];
763 PHPT_PASS_THROUGH_HEADER pide_pt_hdr
, pide_pt_hdr_out
;
765 // get internal deviceid
766 ids
[0] = m_hpt_data
[0] - 1;
767 ids
[1] = m_hpt_data
[1] - 1;
769 memset(¶m
, 0, sizeof(HPT_IOCTL_PARAM
));
771 param
.magic
= HPT_IOCTL_MAGIC
;
772 param
.ctrl_code
= HPT_IOCTL_GET_CHANNEL_INFO_V2
;
773 param
.in
= (unsigned char *)ids
;
774 param
.in_size
= sizeof(unsigned int) * 2;
775 param
.out
= (unsigned char *)&info
;
776 param
.out_size
= sizeof(HPT_CHANNEL_INFO_V2
);
778 if (m_hpt_data
[2]==1) {
779 param
.ctrl_code
= HPT_IOCTL_GET_CHANNEL_INFO
;
780 param
.out_size
= sizeof(HPT_CHANNEL_INFO
);
782 if (ioctl(fd
, HPT_DO_IOCONTROL
, ¶m
)!=0 ||
783 info
.devices
[m_hpt_data
[2]-1]==0) {
787 // perform smart action
788 memset(buff
, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER
));
789 pide_pt_hdr
= (PHPT_PASS_THROUGH_HEADER
)buff
;
791 pide_pt_hdr
->lbamid
= 0x4f;
792 pide_pt_hdr
->lbahigh
= 0xc2;
793 pide_pt_hdr
->command
= ATA_SMART_CMD
;
794 pide_pt_hdr
->id
= info
.devices
[m_hpt_data
[2] - 1];
798 pide_pt_hdr
->feature
=ATA_SMART_READ_VALUES
;
799 pide_pt_hdr
->protocol
=HPT_READ
;
801 case READ_THRESHOLDS
:
802 pide_pt_hdr
->feature
=ATA_SMART_READ_THRESHOLDS
;
803 pide_pt_hdr
->protocol
=HPT_READ
;
806 pide_pt_hdr
->feature
=ATA_SMART_READ_LOG_SECTOR
;
807 pide_pt_hdr
->lbalow
=select
;
808 pide_pt_hdr
->protocol
=HPT_READ
;
811 pide_pt_hdr
->command
=ATA_IDENTIFY_DEVICE
;
812 pide_pt_hdr
->protocol
=HPT_READ
;
815 pide_pt_hdr
->feature
=ATA_SMART_ENABLE
;
818 pide_pt_hdr
->feature
=ATA_SMART_DISABLE
;
821 pide_pt_hdr
->feature
=ATA_SMART_AUTO_OFFLINE
;
822 pide_pt_hdr
->sectorcount
=select
;
825 pide_pt_hdr
->feature
=ATA_SMART_AUTOSAVE
;
826 pide_pt_hdr
->sectorcount
=select
;
828 case IMMEDIATE_OFFLINE
:
829 pide_pt_hdr
->feature
=ATA_SMART_IMMEDIATE_OFFLINE
;
830 pide_pt_hdr
->lbalow
=select
;
834 pide_pt_hdr
->feature
=ATA_SMART_STATUS
;
836 case CHECK_POWER_MODE
:
837 pide_pt_hdr
->command
=ATA_CHECK_POWER_MODE
;
840 memcpy(buff
+sizeof(HPT_PASS_THROUGH_HEADER
), data
, 512);
841 pide_pt_hdr
->feature
=ATA_SMART_WRITE_LOG_SECTOR
;
842 pide_pt_hdr
->lbalow
=select
;
843 pide_pt_hdr
->protocol
=HPT_WRITE
;
846 pout("Unrecognized command %d in highpoint_command_interface()\n"
847 "Please contact " PACKAGE_BUGREPORT
"\n", command
);
851 if (pide_pt_hdr
->protocol
!=0) {
852 pide_pt_hdr
->sectors
= 1;
853 pide_pt_hdr
->sectorcount
= 1;
856 memset(¶m
, 0, sizeof(HPT_IOCTL_PARAM
));
858 param
.magic
= HPT_IOCTL_MAGIC
;
859 param
.ctrl_code
= HPT_IOCTL_IDE_PASS_THROUGH
;
860 param
.in
= (unsigned char *)buff
;
861 param
.in_size
= sizeof(HPT_PASS_THROUGH_HEADER
) + (pide_pt_hdr
->protocol
==HPT_READ
? 0 : pide_pt_hdr
->sectors
* 512);
862 param
.out
= (unsigned char *)buff
+param
.in_size
;
863 param
.out_size
= sizeof(HPT_PASS_THROUGH_HEADER
) + (pide_pt_hdr
->protocol
==HPT_READ
? pide_pt_hdr
->sectors
* 512 : 0);
865 pide_pt_hdr_out
= (PHPT_PASS_THROUGH_HEADER
)param
.out
;
867 if ((ioctl(fd
, HPT_DO_IOCONTROL
, ¶m
)!=0) ||
868 (pide_pt_hdr_out
->command
& 1)) {
872 if (command
==STATUS_CHECK
)
874 unsigned const char normal_lo
=0x4f, normal_hi
=0xc2;
875 unsigned const char failed_lo
=0xf4, failed_hi
=0x2c;
876 unsigned char low
,high
;
878 high
= pide_pt_hdr_out
->lbahigh
;
879 low
= pide_pt_hdr_out
->lbamid
;
881 // Cyl low and Cyl high unchanged means "Good SMART status"
882 if (low
==normal_lo
&& high
==normal_hi
)
885 // These values mean "Bad SMART status"
886 if (low
==failed_lo
&& high
==failed_hi
)
889 // We haven't gotten output that makes sense; print out some debugging info
891 sprintf(buf
,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
892 (int)pide_pt_hdr_out
->command
,
893 (int)pide_pt_hdr_out
->feature
,
894 (int)pide_pt_hdr_out
->sectorcount
,
895 (int)pide_pt_hdr_out
->lbalow
,
896 (int)pide_pt_hdr_out
->lbamid
,
897 (int)pide_pt_hdr_out
->lbahigh
,
898 (int)pide_pt_hdr_out
->sectors
);
899 printwarning(BAD_SMART
,buf
);
901 else if (command
==CHECK_POWER_MODE
)
902 data
[0] = pide_pt_hdr_out
->sectorcount
& 0xff;
903 else if (pide_pt_hdr
->protocol
==HPT_READ
)
904 memcpy(data
, (unsigned char *)buff
+ 2 * sizeof(HPT_PASS_THROUGH_HEADER
),
905 pide_pt_hdr
->sectors
* 512);
910 /////////////////////////////////////////////////////////////////////////////
911 /// Implement standard SCSI support with old functions
913 class freebsd_scsi_device
914 : public /*implements*/ scsi_device
,
915 public /*extends*/ freebsd_smart_device
918 freebsd_scsi_device(smart_interface
* intf
, const char * dev_name
, const char * req_type
);
920 virtual smart_device
* autodetect_open();
922 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
926 virtual bool close();
930 struct cam_device
*m_camdev
;
933 bool freebsd_scsi_device::open(){
934 const char *dev
= get_dev_name();
936 if ((m_camdev
= cam_open_device(dev
, O_RDWR
)) == NULL
) {
940 set_fd(m_camdev
->fd
);
944 bool freebsd_scsi_device::close(){
945 cam_close_device(m_camdev
);
950 freebsd_scsi_device::freebsd_scsi_device(smart_interface
* intf
,
951 const char * dev_name
, const char * req_type
)
952 : smart_device(intf
, dev_name
, "scsi", req_type
),
953 freebsd_smart_device("SCSI")
958 bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io
* iop
)
960 int report
=con
->reportscsiioctl
;
965 const unsigned char * ucp
= iop
->cmnd
;
968 np
= scsi_get_opcode_name(ucp
[0]);
969 pout(" [%s: ", np
? np
: "<unknown opcode>");
970 for (k
= 0; k
< iop
->cmnd_len
; ++k
)
971 pout("%02x ", ucp
[k
]);
973 (DXFER_TO_DEVICE
== iop
->dxfer_dir
) && (iop
->dxferp
)) {
974 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
976 pout("]\n Outgoing data, len=%d%s:\n", (int)iop
->dxfer_len
,
977 (trunc
? " [only first 256 bytes shown]" : ""));
978 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
985 warnx("error: camdev=0!");
989 if (!(ccb
= cam_getccb(m_camdev
))) {
990 warnx("error allocating ccb");
994 // clear out structure, except for header that was filled in for us
995 bzero(&(&ccb
->ccb_h
)[1],
996 sizeof(struct ccb_scsiio
) - sizeof(struct ccb_hdr
));
998 cam_fill_csio(&ccb
->csio
,
1001 /* flags */ (iop
->dxfer_dir
== DXFER_NONE
? CAM_DIR_NONE
:(iop
->dxfer_dir
== DXFER_FROM_DEVICE
? CAM_DIR_IN
: CAM_DIR_OUT
)),
1002 /* tagaction */ MSG_SIMPLE_Q_TAG
,
1003 /* dataptr */ iop
->dxferp
,
1004 /* datalen */ iop
->dxfer_len
,
1005 /* senselen */ iop
->max_sense_len
,
1006 /* cdblen */ iop
->cmnd_len
,
1007 /* timout (converted to seconds) */ iop
->timeout
*1000);
1008 memcpy(ccb
->csio
.cdb_io
.cdb_bytes
,iop
->cmnd
,iop
->cmnd_len
);
1010 if (cam_send_ccb(m_camdev
,ccb
) < 0) {
1011 warn("error sending SCSI ccb");
1012 #if (FREEBSDVER > 500000)
1013 cam_error_print(m_camdev
,ccb
,CAM_ESF_ALL
,CAM_EPF_ALL
,stderr
);
1019 if (((ccb
->ccb_h
.status
& CAM_STATUS_MASK
) != CAM_REQ_CMP
) && ((ccb
->ccb_h
.status
& CAM_STATUS_MASK
) != CAM_SCSI_STATUS_ERROR
)) {
1020 #if (FREEBSDVER > 500000)
1021 cam_error_print(m_camdev
,ccb
,CAM_ESF_ALL
,CAM_EPF_ALL
,stderr
);
1028 memcpy(iop
->sensep
,&(ccb
->csio
.sense_data
),sizeof(struct scsi_sense_data
));
1029 iop
->resp_sense_len
= sizeof(struct scsi_sense_data
);
1032 iop
->scsi_status
= ccb
->csio
.scsi_status
;
1039 pout(" status=0\n");
1040 trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
1042 pout(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
1043 (trunc
? " [only first 256 bytes shown]" : ""));
1044 dStrHex(iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
1051 /////////////////////////////////////////////////////////////////////////////
1052 /// Implement CCISS RAID support with old functions
1054 class freebsd_cciss_device
1055 : public /*implements*/ scsi_device
,
1056 public /*extends*/ freebsd_smart_device
1059 freebsd_cciss_device(smart_interface
* intf
, const char * name
, unsigned char disknum
);
1061 virtual bool scsi_pass_through(scsi_cmnd_io
* iop
);
1062 virtual bool open();
1065 unsigned char m_disknum
; ///< Disk number.
1068 bool freebsd_cciss_device::open()
1070 const char *dev
= get_dev_name();
1072 #ifndef HAVE_DEV_CISS_CISSIO_H
1073 pout("CCISS support is not available in this build of smartmontools,\n"
1074 "/usr/src/sys/dev/ciss/cissio.h was not available at build time.\n\n");
1077 if ((fd
= ::open(dev
,O_RDWR
))<0) {
1085 freebsd_cciss_device::freebsd_cciss_device(smart_interface
* intf
,
1086 const char * dev_name
, unsigned char disknum
)
1087 : smart_device(intf
, dev_name
, "cciss", "cciss"),
1088 freebsd_smart_device("SCSI"),
1091 set_info().info_name
= strprintf("%s [cciss_disk_%02d]", dev_name
, disknum
);
1094 bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io
* iop
)
1096 #ifdef HAVE_DEV_CISS_CISSIO_H
1097 int status
= cciss_io_interface(get_fd(), m_disknum
, iop
, con
->reportscsiioctl
);
1099 return set_err(-status
);
1107 /////////////////////////////////////////////////////////////////////////////
1108 /// SCSI open with autodetection support
1110 smart_device
* freebsd_scsi_device::autodetect_open()
1116 // No Autodetection if device type was specified by user
1117 if (*get_req_type())
1120 // The code below is based on smartd.cpp:SCSIFilterKnown()
1123 unsigned char req_buff
[64] = {0, };
1125 if (scsiStdInquiry(this, req_buff
, req_len
)) {
1126 // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
1127 // watch this spot ... other devices could lock up here
1129 if (scsiStdInquiry(this, req_buff
, req_len
)) {
1130 // device doesn't like INQUIRY commands
1132 set_err(EIO
, "INQUIRY failed");
1137 int avail_len
= req_buff
[4] + 5;
1138 int len
= (avail_len
< req_len
? avail_len
: req_len
);
1142 // Use INQUIRY to detect type
1145 if (!memcmp(req_buff
+ 8, "3ware", 5) || !memcmp(req_buff
+ 8, "AMCC", 4)) {
1147 set_err(EINVAL
, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
1148 "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
1154 smart_device
* newdev
= smi()->autodetect_sat_device(this, req_buff
, len
);
1156 // NOTE: 'this' is now owned by '*newdev'
1160 // Nothing special found
1165 /////////////////////////////////////////////////////////////////////////////
1166 /// Implement platform interface with old functions.
1168 class freebsd_smart_interface
1169 : public /*implements*/ smart_interface
1172 virtual std::string
get_os_version_str();
1174 virtual std::string
get_app_examples(const char * appname
);
1176 virtual bool scan_smart_devices(smart_device_list
& devlist
, const char * type
,
1177 const char * pattern
= 0);
1180 virtual ata_device
* get_ata_device(const char * name
, const char * type
);
1182 #if FREEBSDVER > 800100
1183 virtual ata_device
* get_atacam_device(const char * name
, const char * type
);
1186 virtual scsi_device
* get_scsi_device(const char * name
, const char * type
);
1188 virtual smart_device
* autodetect_smart_device(const char * name
);
1190 virtual smart_device
* get_custom_smart_device(const char * name
, const char * type
);
1192 virtual std::string
get_valid_custom_dev_types_str();
1196 //////////////////////////////////////////////////////////////////////
1198 std::string
freebsd_smart_interface::get_os_version_str()
1200 struct utsname osname
;
1202 return strprintf("%s %s %s", osname
.sysname
, osname
.release
, osname
.machine
);
1205 std::string
freebsd_smart_interface::get_app_examples(const char * appname
)
1207 if (!strcmp(appname
, "smartctl"))
1208 return smartctl_examples
;
1212 ata_device
* freebsd_smart_interface::get_ata_device(const char * name
, const char * type
)
1214 return new freebsd_ata_device(this, name
, type
);
1217 #if FREEBSDVER > 800100
1218 ata_device
* freebsd_smart_interface::get_atacam_device(const char * name
, const char * type
)
1220 return new freebsd_atacam_device(this, name
, type
);
1224 scsi_device
* freebsd_smart_interface::get_scsi_device(const char * name
, const char * type
)
1226 return new freebsd_scsi_device(this, name
, type
);
1229 // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
1230 // devices on system despite of it's names
1232 // If any errors occur, leave errno set as it was returned by the
1233 // system call, and return <0.
1236 // names: resulting array
1237 // show_all - export duplicate device name or not
1241 // >=0: number of discovered devices
1243 int get_dev_names_cam(char*** names
, bool show_all
) {
1248 int bufsize
, fd
= -1;
1249 int skip_device
= 0, skip_bus
= 0, changed
= 0;
1250 char *devname
= NULL
;
1253 // in case of non-clean exit
1255 ccb
.cdm
.matches
= NULL
;
1257 if ((fd
= open(XPT_DEVICE
, O_RDWR
)) == -1) {
1258 if (errno
== ENOENT
) /* There are no CAM device on this computer */
1261 pout("%s control device couldn't opened: %s\n", XPT_DEVICE
, strerror(errno
));
1266 // allocate space for up to MAX_NUM_DEV number of ATA devices
1267 mp
= (char **)calloc(MAX_NUM_DEV
, sizeof(char*));
1270 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__
);
1275 bzero(&ccb
, sizeof(union ccb
));
1277 ccb
.ccb_h
.path_id
= CAM_XPT_PATH_ID
;
1278 ccb
.ccb_h
.target_id
= CAM_TARGET_WILDCARD
;
1279 ccb
.ccb_h
.target_lun
= CAM_LUN_WILDCARD
;
1281 ccb
.ccb_h
.func_code
= XPT_DEV_MATCH
;
1282 bufsize
= sizeof(struct dev_match_result
) * MAX_NUM_DEV
;
1283 ccb
.cdm
.match_buf_len
= bufsize
;
1284 ccb
.cdm
.matches
= (struct dev_match_result
*)malloc(bufsize
);
1285 if (ccb
.cdm
.matches
== NULL
) {
1287 pout("can't malloc memory for matches on line %d\n", __LINE__
);
1291 ccb
.cdm
.num_matches
= 0;
1292 ccb
.cdm
.num_patterns
= 0;
1293 ccb
.cdm
.pattern_buf_len
= 0;
1296 * We do the ioctl multiple times if necessary, in case there are
1297 * more than MAX_NUM_DEV nodes in the EDT.
1300 if (ioctl(fd
, CAMIOCOMMAND
, &ccb
) == -1) {
1302 pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno
));
1307 if ((ccb
.ccb_h
.status
!= CAM_REQ_CMP
)
1308 || ((ccb
.cdm
.status
!= CAM_DEV_MATCH_LAST
)
1309 && (ccb
.cdm
.status
!= CAM_DEV_MATCH_MORE
))) {
1310 pout("got CAM error %#x, CDM error %d\n", ccb
.ccb_h
.status
, ccb
.cdm
.status
);
1316 for (i
= 0; i
< ccb
.cdm
.num_matches
&& n
< MAX_NUM_DEV
; i
++) {
1317 struct bus_match_result
*bus_result
;
1318 struct device_match_result
*dev_result
;
1319 struct periph_match_result
*periph_result
;
1321 if (ccb
.cdm
.matches
[i
].type
== DEV_MATCH_BUS
) {
1322 bus_result
= &ccb
.cdm
.matches
[i
].result
.bus_result
;
1324 if (strcmp(bus_result
->dev_name
,"ata") == 0 /* ATAPICAM devices will be probed as ATA devices, skip'em there */
1325 || strcmp(bus_result
->dev_name
,"xpt") == 0) /* skip XPT bus at all */
1330 } else if (ccb
.cdm
.matches
[i
].type
== DEV_MATCH_DEVICE
) {
1331 dev_result
= &ccb
.cdm
.matches
[i
].result
.device_result
;
1333 if (dev_result
->flags
& DEV_RESULT_UNCONFIGURED
|| skip_bus
== 1)
1338 // /* Shall we skip non T_DIRECT devices ? */
1339 // if (dev_result->inq_data.device != T_DIRECT)
1342 } else if (ccb
.cdm
.matches
[i
].type
== DEV_MATCH_PERIPH
&&
1343 (skip_device
== 0 || show_all
)) {
1344 /* One device may be populated as many peripherals (pass0 & da0 for example).
1345 * We are searching for latest name
1347 periph_result
= &ccb
.cdm
.matches
[i
].result
.periph_result
;
1349 asprintf(&devname
, "%s%s%d", _PATH_DEV
, periph_result
->periph_name
, periph_result
->unit_number
);
1350 if (devname
== NULL
) {
1352 pout("Out of memory constructing scan SCSI device list (on line %d)\n", __LINE__
);
1358 if ((changed
== 1 || show_all
) && devname
!= NULL
) {
1361 bytes
+=1+strlen(mp
[n
]);
1367 } while ((ccb
.ccb_h
.status
== CAM_REQ_CMP
) && (ccb
.cdm
.status
== CAM_DEV_MATCH_MORE
) && n
< MAX_NUM_DEV
);
1369 if (devname
!= NULL
) {
1372 bytes
+=1+strlen(mp
[n
]);
1376 mp
= (char **)reallocf(mp
,n
*(sizeof (char*))); // shrink to correct size
1377 bytes
+= (n
)*(sizeof(char*)); // and set allocated byte count
1380 free(ccb
.cdm
.matches
);
1395 // we are using ATA subsystem enumerator to found all ATA devices on system
1396 // despite of it's names
1398 // If any errors occur, leave errno set as it was returned by the
1399 // system call, and return <0.
1403 // >=0: number of discovered devices
1404 int get_dev_names_ata(char*** names
) {
1405 struct ata_ioc_devices devices
;
1406 int fd
=-1,maxchannel
,serrno
=-1,n
=0;
1411 if ((fd
= open(ATA_DEVICE
, O_RDWR
)) < 0) {
1412 if (errno
== ENOENT
) /* There are no ATA device on this computer */
1415 pout("%s control device can't be opened: %s\n", ATA_DEVICE
, strerror(errno
));
1420 if (ioctl(fd
, IOCATAGMAXCHANNEL
, &maxchannel
) < 0) {
1422 pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno
));
1427 // allocate space for up to MAX_NUM_DEV number of ATA devices
1428 mp
= (char **)calloc(MAX_NUM_DEV
, sizeof(char*));
1431 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__
);
1436 for (devices
.channel
= 0; devices
.channel
< maxchannel
&& n
< MAX_NUM_DEV
; devices
.channel
++) {
1439 if (ioctl(fd
, IOCATADEVICES
, &devices
) < 0) {
1441 continue; /* such channel not exist */
1442 pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE
, devices
.channel
, strerror(errno
));
1446 for (j
=0;j
<=1 && n
<MAX_NUM_DEV
;j
++) {
1447 if (devices
.name
[j
][0] != '\0') {
1448 asprintf(mp
+n
, "%s%s", _PATH_DEV
, devices
.name
[j
]);
1449 if (mp
[n
] == NULL
) {
1450 pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__
);
1454 bytes
+=1+strlen(mp
[n
]);
1459 mp
= (char **)reallocf(mp
,n
*(sizeof (char*))); // shrink to correct size
1460 if (mp
== NULL
&& n
> 0 ) { // reallocf never fail for size=0, but may return NULL
1462 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__
);
1466 bytes
+= (n
)*(sizeof(char*)); // and set allocated byte count
1485 bool freebsd_smart_interface::scan_smart_devices(smart_device_list
& devlist
,
1486 const char * type
, const char * pattern
/*= 0*/)
1489 set_err(EINVAL
, "DEVICESCAN with pattern not implemented yet");
1494 char * * atanames
= 0; int numata
= 0;
1495 if (!type
|| !strcmp(type
, "ata")) {
1496 numata
= get_dev_names_ata(&atanames
);
1503 char * * scsinames
= 0; int numscsi
= 0;
1504 if (!type
|| !strcmp(type
, "scsi")) { // do not export duplicated names
1505 numscsi
= get_dev_names_cam(&scsinames
,0);
1516 for (i
= 0; i
< numata
; i
++) {
1517 ata_device
* atadev
= get_ata_device(atanames
[i
], type
);
1519 devlist
.push_back(atadev
);
1522 for (i
= 0; i
< numscsi
; i
++) {
1523 if(!*type
) { // try USB autodetection if no type specified
1524 smart_device
* smartdev
= autodetect_smart_device(scsinames
[i
]);
1526 devlist
.push_back(smartdev
);
1529 scsi_device
* scsidev
= get_scsi_device(scsinames
[i
], type
);
1531 devlist
.push_back(scsidev
);
1538 #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
1539 static char done
[USB_MAX_DEVICES
];
1541 static int usbdevinfo(int f
, int a
, int rec
, int busno
, unsigned short & vendor_id
,
1542 unsigned short & product_id
, unsigned short & version
)
1545 struct usb_device_info di
;
1549 snprintf(devname
, sizeof(devname
),"umass%d",busno
);
1552 e
= ioctl(f
, USB_DEVICEINFO
, &di
);
1555 printf("addr %d: I/O error\n", a
);
1561 for (i
= 0; i
< USB_MAX_DEVNAMES
; i
++) {
1562 if (di
.udi_devnames
[i
][0]) {
1563 if(strcmp(di
.udi_devnames
[i
],devname
)==0) {
1565 vendor_id
= di
.udi_vendorNo
;
1566 product_id
= di
.udi_productNo
;
1567 version
= di
.udi_releaseNo
;
1575 for (p
= 0; p
< di
.udi_nports
; p
++) {
1576 int s
= di
.udi_ports
[p
];
1577 if (s
>= USB_MAX_DEVICES
) {
1581 printf("addr 0 should never happen!\n");
1583 if(usbdevinfo(f
, s
, 1, busno
, vendor_id
, product_id
, version
)) return 1;
1591 static int usbdevlist(int busno
,unsigned short & vendor_id
,
1592 unsigned short & product_id
, unsigned short & version
)
1594 #if (FREEBSDVER >= 800000) // libusb2 interface
1595 struct libusb20_device
*pdev
= NULL
;
1596 struct libusb20_backend
*pbe
;
1597 uint32_t matches
= 0;
1598 char buf
[128]; // do not change!
1601 struct LIBUSB20_DEVICE_DESC_DECODED
*pdesc
;
1603 pbe
= libusb20_be_alloc_default();
1605 while ((pdev
= libusb20_be_device_foreach(pbe
, pdev
))) {
1608 if (libusb20_dev_open(pdev
, 0)) {
1609 warnx("libusb20_dev_open: could not open device");
1613 pdesc
=libusb20_dev_get_device_desc(pdev
);
1615 snprintf(devname
, sizeof(devname
),"umass%d:",busno
);
1616 for (n
= 0; n
!= 255; n
++) {
1617 if (libusb20_dev_get_iface_desc(pdev
, n
, buf
, sizeof(buf
)))
1621 if(strncmp(buf
,devname
,strlen(devname
))==0){
1623 vendor_id
= pdesc
->idVendor
;
1624 product_id
= pdesc
->idProduct
;
1625 version
= pdesc
->bcdDevice
;
1626 libusb20_dev_close(pdev
);
1627 libusb20_be_free(pbe
);
1632 libusb20_dev_close(pdev
);
1636 printf("No device match or lack of permissions.\n");
1639 libusb20_be_free(pbe
);
1642 #else // freebsd < 8.0 USB stack, ioctl interface
1648 for (ncont
= 0, i
= 0; i
< 10; i
++) {
1649 snprintf(buf
, sizeof(buf
), "%s%d", USBDEV
, i
);
1650 f
= open(buf
, O_RDONLY
);
1652 memset(done
, 0, sizeof done
);
1653 for (a
= 1; a
< USB_MAX_DEVICES
; a
++) {
1655 rc
= usbdevinfo(f
, a
, 1, busno
,vendor_id
, product_id
, version
);
1662 if (errno
== ENOENT
|| errno
== ENXIO
)
1672 smart_device
* freebsd_smart_interface::autodetect_smart_device(const char * name
)
1674 unsigned short vendor_id
= 0, product_id
= 0, version
= 0;
1675 struct cam_device
*cam_dev
;
1681 // if dev_name null, or string length zero
1682 if (!name
|| !(len
= strlen(name
)))
1686 char * * atanames
= 0; int numata
= 0;
1687 numata
= get_dev_names_ata(&atanames
);
1689 // check ATA/ATAPI devices
1690 for (i
= 0; i
< numata
; i
++) {
1691 if(!strcmp(atanames
[i
],name
)) {
1692 return new freebsd_ata_device(this, name
, "");
1698 pout("Unable to get ATA device list\n");
1702 char * * scsinames
= 0; int numscsi
= 0;
1703 numscsi
= get_dev_names_cam(&scsinames
, 1);
1705 // check all devices on CAM bus
1706 for (i
= 0; i
< numscsi
; i
++) {
1707 if(strcmp(scsinames
[i
],name
)==0)
1708 { // our disk device is CAM
1709 if ((cam_dev
= cam_open_device(name
, O_RDWR
)) == NULL
) {
1716 bzero(&(&ccb
.ccb_h
)[1], PATHINQ_SETTINGS_SIZE
);
1717 ccb
.ccb_h
.func_code
= XPT_PATH_INQ
; // send PATH_INQ to the device
1718 if (ioctl(cam_dev
->fd
, CAMIOCOMMAND
, &ccb
) == -1) {
1719 warn("Get Transfer Settings CCB failed\n"
1720 "%s", strerror(errno
));
1721 cam_close_device(cam_dev
);
1724 // now check if we are working with USB device, see umass.c
1725 if(strcmp(ccb
.cpi
.dev_name
,"umass-sim") == 0) { // USB device found
1726 usbdevlist(bus
,vendor_id
, product_id
, version
);
1727 int bus
=ccb
.cpi
.unit_number
; // unit_number will match umass number
1728 cam_close_device(cam_dev
);
1729 if(usbdevlist(bus
,vendor_id
, product_id
, version
)){
1730 const char * usbtype
= get_usb_dev_type_by_id(vendor_id
, product_id
, version
);
1732 return get_sat_device(usbtype
, new freebsd_scsi_device(this, name
, ""));
1736 #if FREEBSDVER > 800100
1737 // check if we have ATA device connected to CAM (ada)
1738 if(ccb
.cpi
.protocol
== PROTO_ATA
){
1739 cam_close_device(cam_dev
);
1740 return new freebsd_atacam_device(this, name
, "");
1743 // close cam device, we don`t need it anymore
1744 cam_close_device(cam_dev
);
1745 // handle as usual scsi
1746 return new freebsd_scsi_device(this, name
, "");
1751 if(numscsi
<0) pout("Unable to get CAM device list\n");
1753 // device type unknown
1758 smart_device
* freebsd_smart_interface::get_custom_smart_device(const char * name
, const char * type
)
1761 static const char * fbsd_dev_twe_ctrl
= "/dev/twe";
1762 static const char * fbsd_dev_twa_ctrl
= "/dev/twa";
1763 int disknum
= -1, n1
= -1, n2
= -1, contr
= -1;
1765 if (sscanf(type
, "3ware,%n%d%n", &n1
, &disknum
, &n2
) == 1 || n1
== 6) {
1766 if (n2
!= (int)strlen(type
)) {
1767 set_err(EINVAL
, "Option -d 3ware,N requires N to be a non-negative integer");
1770 if (!(0 <= disknum
&& disknum
<= 127)) {
1771 set_err(EINVAL
, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum
);
1775 // guess 3ware device type based on device name
1776 if (!strncmp(fbsd_dev_twa_ctrl
, name
, strlen(fbsd_dev_twa_ctrl
))){
1777 contr
=CONTROLLER_3WARE_9000_CHAR
;
1779 if (!strncmp(fbsd_dev_twe_ctrl
, name
, strlen(fbsd_dev_twe_ctrl
))){
1780 contr
=CONTROLLER_3WARE_678K_CHAR
;
1784 set_err(EINVAL
, "3ware controller type unknown, use %sX or %sX devices",
1785 fbsd_dev_twe_ctrl
, fbsd_dev_twa_ctrl
);
1788 return new freebsd_escalade_device(this, name
, contr
, disknum
);
1792 int controller
= -1, channel
= -1; disknum
= 1;
1793 n1
= n2
= -1; int n3
= -1;
1794 if (sscanf(type
, "hpt,%n%d/%d%n/%d%n", &n1
, &controller
, &channel
, &n2
, &disknum
, &n3
) >= 2 || n1
== 4) {
1795 int len
= strlen(type
);
1796 if (!(n2
== len
|| n3
== len
)) {
1797 set_err(EINVAL
, "Option '-d hpt,L/M/N' supports 2-3 items");
1800 if (!(1 <= controller
&& controller
<= 8)) {
1801 set_err(EINVAL
, "Option '-d hpt,L/M/N' invalid controller id L supplied");
1804 if (!(1 <= channel
&& channel
<= 8)) {
1805 set_err(EINVAL
, "Option '-d hpt,L/M/N' invalid channel number M supplied");
1808 if (!(1 <= disknum
&& disknum
<= 15)) {
1809 set_err(EINVAL
, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
1812 return new freebsd_highpoint_device(this, name
, controller
, channel
, disknum
);
1816 disknum
= n1
= n2
= -1;
1817 if (sscanf(type
, "cciss,%n%d%n", &n1
, &disknum
, &n2
) == 1 || n1
== 6) {
1818 if (n2
!= (int)strlen(type
)) {
1819 set_err(EINVAL
, "Option -d cciss,N requires N to be a non-negative integer");
1822 if (!(0 <= disknum
&& disknum
<= 15)) {
1823 set_err(EINVAL
, "Option -d cciss,N (N=%d) must have 0 <= N <= 15", disknum
);
1826 return new freebsd_cciss_device(this, name
, disknum
);
1828 #if FREEBSDVER > 800100
1830 if(!strcmp(type
,"atacam"))
1831 return new freebsd_atacam_device(this, name
, "");
1837 std::string
freebsd_smart_interface::get_valid_custom_dev_types_str()
1839 return "3ware,N, hpt,L/M/N, cciss,N"
1840 #if FREEBSDVER > 800100
1848 /////////////////////////////////////////////////////////////////////////////
1849 /// Initialize platform interface and register with smi()
1851 void smart_interface::init()
1853 static os_freebsd::freebsd_smart_interface the_interface
;
1854 smart_interface::set(&the_interface
);