]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - os_freebsd.cpp
Imported Upstream version 5.40+svn3296
[mirror_smartmontools-debian.git] / os_freebsd.cpp
CommitLineData
832b75ed
GG
1/*
2 * os_freebsd.c
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
a23d5117 6 * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net>
832b75ed
GG
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18#include <stdio.h>
19#include <sys/types.h>
20#include <dirent.h>
21#include <fcntl.h>
22#include <err.h>
cfbba5b9 23#include <errno.h>
832b75ed
GG
24#include <camlib.h>
25#include <cam/scsi/scsi_message.h>
2127e193 26#include <cam/scsi/scsi_pass.h>
1953ff6d
GG
27#if defined(__DragonFly__)
28#include <sys/nata.h>
29#else
832b75ed 30#include <sys/ata.h>
1953ff6d 31#endif
832b75ed
GG
32#include <sys/stat.h>
33#include <unistd.h>
832b75ed 34#include <glob.h>
832b75ed 35#include <stddef.h>
2127e193
GI
36#include <paths.h>
37#include <sys/utsname.h>
832b75ed
GG
38
39#include "config.h"
40#include "int64.h"
41#include "atacmds.h"
42#include "scsicmds.h"
a37e7145 43#include "cciss.h"
832b75ed
GG
44#include "utility.h"
45#include "os_freebsd.h"
46
2127e193
GI
47#include "dev_interface.h"
48#include "dev_ata_cmd_set.h"
49
50#define USBDEV "/dev/usb"
54965743
GI
51#if defined(__FreeBSD_version)
52
53// This way we define one variable for the GNU/kFreeBSD and FreeBSD
54#define FREEBSDVER __FreeBSD_version
55#else
56#define FREEBSDVER __FreeBSD_kernel_version
57#endif
58
59#if (FREEBSDVER >= 800000)
60#include <libusb20_desc.h>
61#include <libusb20.h>
cfbba5b9
GI
62#elif defined(__DragonFly__)
63#include <bus/usb/usb.h>
64#include <bus/usb/usbhid.h>
54965743
GI
65#else
66#include <dev/usb/usb.h>
67#include <dev/usb/usbhid.h>
68#endif
832b75ed 69
eb07ddf2
GI
70#define CONTROLLER_3WARE_9000_CHAR 0x01
71#define CONTROLLER_3WARE_678K_CHAR 0x02
a37e7145 72
eb07ddf2
GI
73#ifndef PATHINQ_SETTINGS_SIZE
74#define PATHINQ_SETTINGS_SIZE 128
75#endif
832b75ed 76
cfbba5b9 77const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3264 2011-02-21 15:52:04Z chrfranke $" \
eb07ddf2 78ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
54965743 79
832b75ed
GG
80#define NO_RETURN 0
81#define BAD_SMART 1
82#define NO_DISK_3WARE 2
83#define BAD_KERNEL 3
84#define MAX_MSG 3
85
86// Utility function for printing warnings
87void 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",
54965743 91
832b75ed 92 "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
54965743 93
832b75ed 94 "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
54965743 95
832b75ed
GG
96 "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
97 };
98
99 if (msgNo >= 0 && msgNo <= MAX_MSG) {
100 if (!printed[msgNo]) {
101 printed[msgNo] = 1;
102 pout("%s", message[msgNo]);
103 if (extra)
104 pout("%s",extra);
105 }
106 }
107 return;
108}
109
2127e193 110// Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c
832b75ed 111
2127e193
GI
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) )
4d59bff9 115
2127e193
GI
116#ifndef ATA_DEVICE
117#define ATA_DEVICE "/dev/ata"
832b75ed 118#endif
832b75ed 119
2127e193
GI
120// global variable holding byte count of allocated memory
121long long bytes;
832b75ed 122
2127e193 123/////////////////////////////////////////////////////////////////////////////
832b75ed 124
2127e193 125namespace os_freebsd { // No need to publish anything, name provided for Doxygen
832b75ed 126
2127e193
GI
127/////////////////////////////////////////////////////////////////////////////
128/// Implement shared open/close routines with old functions.
832b75ed 129
2127e193
GI
130class freebsd_smart_device
131: virtual public /*implements*/ smart_device
132{
133public:
134 explicit freebsd_smart_device(const char * mode)
135 : smart_device(never_called),
136 m_fd(-1), m_mode(mode) { }
832b75ed 137
2127e193 138 virtual ~freebsd_smart_device() throw();
832b75ed 139
2127e193 140 virtual bool is_open() const;
832b75ed 141
2127e193 142 virtual bool open();
832b75ed 143
2127e193 144 virtual bool close();
832b75ed 145
2127e193
GI
146protected:
147 /// Return filedesc for derived classes.
148 int get_fd() const
149 { return m_fd; }
832b75ed 150
eb07ddf2
GI
151 void set_fd(int fd)
152 { m_fd = fd; }
153
2127e193
GI
154private:
155 int m_fd; ///< filedesc, -1 if not open.
156 const char * m_mode; ///< Mode string for deviceopen().
157};
832b75ed 158
54965743
GI
159#ifdef __GLIBC__
160static inline void * reallocf(void *ptr, size_t size) {
161 void *rv = realloc(ptr, size);
f4ebf3d1 162 if((rv == NULL) && (size != 0))
54965743
GI
163 free(ptr);
164 return rv;
165 }
166#endif
2127e193
GI
167
168freebsd_smart_device::~freebsd_smart_device() throw()
a37e7145 169{
2127e193
GI
170 if (m_fd >= 0)
171 os_freebsd::freebsd_smart_device::close();
a37e7145
GG
172}
173
2127e193
GI
174// migration from the old_style
175unsigned char m_controller_type;
176unsigned char m_controller_port;
832b75ed 177
2127e193
GI
178// examples for smartctl
179static const char smartctl_examples[] =
54965743 180 "=================================================== SMARTCTL EXAMPLES =====\n\n"
2127e193
GI
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"
54965743
GI
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"
195
2127e193 196 ;
832b75ed 197
2127e193
GI
198bool freebsd_smart_device::is_open() const
199{
200 return (m_fd >= 0);
201}
832b75ed 202
832b75ed 203
2127e193
GI
204bool freebsd_smart_device::open()
205{
2127e193 206 const char *dev = get_dev_name();
eb07ddf2
GI
207 if ((m_fd = ::open(dev,O_RDONLY))<0) {
208 set_err(errno);
2127e193
GI
209 return false;
210 }
211 return true;
212}
213
214bool freebsd_smart_device::close()
215{
2127e193 216 int failed = 0;
2127e193 217 // close device, if open
eb07ddf2
GI
218 if (is_open())
219 failed=::close(get_fd());
220
221 set_fd(-1);
54965743 222
54965743 223 if(failed) return false;
eb07ddf2 224 else return true;
2127e193
GI
225}
226
227/////////////////////////////////////////////////////////////////////////////
a23d5117 228/// Implement standard ATA support
2127e193
GI
229
230class freebsd_ata_device
a23d5117 231: public /*implements*/ ata_device,
2127e193
GI
232 public /*extends*/ freebsd_smart_device
233{
234public:
235 freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
a23d5117 236 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
2127e193 237
2127e193 238protected:
eb07ddf2 239 virtual int do_cmd(struct ata_ioc_request* request);
2127e193
GI
240};
241
242freebsd_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")
245{
246}
247
eb07ddf2
GI
248int freebsd_ata_device::do_cmd( struct ata_ioc_request* request)
249{
250 int fd = get_fd();
251 return ioctl(fd, IOCATAREQUEST, request);
252}
253
a23d5117
GI
254
255
256bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
257{
7f0798ef
GI
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
262 )
a23d5117
GI
263 return false;
264
265 struct ata_ioc_request request;
266 bzero(&request,sizeof(struct ata_ioc_request));
267
268 request.timeout=SCSI_TIMEOUT_DEFAULT;
269 request.u.ata.command=in.in_regs.command;
270 request.u.ata.feature=in.in_regs.features;
271
272 request.u.ata.count = in.in_regs.sector_count_16;
273 request.u.ata.lba = in.in_regs.lba_48;
274
275 switch (in.direction) {
276 case ata_cmd_in::no_data:
277 request.flags=ATA_CMD_CONTROL;
278 break;
279 case ata_cmd_in::data_in:
280 request.flags=ATA_CMD_READ;
281 request.data=(char *)in.buffer;
282 request.count=in.size;
283 break;
284 case ata_cmd_in::data_out:
285 request.flags=ATA_CMD_WRITE;
286 request.data=(char *)in.buffer;
287 request.count=in.size;
288 break;
289 default:
290 return set_err(ENOSYS);
291 }
292
293 clear_err();
294 errno = 0;
295 if (do_cmd(&request))
296 return set_err(errno);
297 if (request.error)
298 return set_err(EIO, "request failed, error code 0x%02x", request.error);
299
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;
303
304
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)
309 {
310 unsigned const char normal_lo=0x4f, normal_hi=0xc2;
311 unsigned const char failed_lo=0xf4, failed_hi=0x2c;
312
313#if (FREEBSDVER < 502000)
314 printwarning(NO_RETURN,NULL);
315#endif
316
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))
321
322 {
323 // We haven't gotten output that makes sense; print out some debugging info
324 char buf[512];
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),
332 (int)request.error);
333 printwarning(BAD_SMART,buf);
334 out.out_regs.lba_high = failed_hi;
335 out.out_regs.lba_mid = failed_lo;
336 }
337 }
338
339 return true;
340}
341
eb07ddf2
GI
342#if FREEBSDVER > 800100
343class freebsd_atacam_device : public freebsd_ata_device
344{
345public:
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)
348 {}
349
350 virtual bool open();
351 virtual bool close();
352
353protected:
354 int m_fd;
355 struct cam_device *m_camdev;
356
357 virtual int do_cmd( struct ata_ioc_request* request);
358};
359
360bool freebsd_atacam_device::open(){
361 const char *dev = get_dev_name();
362
363 if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
364 set_err(errno);
365 return false;
366 }
367 set_fd(m_camdev->fd);
368 return true;
369}
370
371bool freebsd_atacam_device::close(){
372 cam_close_device(m_camdev);
373 set_fd(-1);
374 return true;
375}
376
377int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request)
378{
379 union ccb ccb;
380 int camflags;
381
382 memset(&ccb, 0, sizeof(ccb));
383
384 if (request->count == 0)
385 camflags = CAM_DIR_NONE;
386 else if (request->flags == ATA_CMD_READ)
387 camflags = CAM_DIR_IN;
388 else
389 camflags = CAM_DIR_OUT;
390
391 cam_fill_ataio(&ccb.ataio,
392 0,
393 NULL,
394 camflags,
395 MSG_SIMPLE_Q_TAG,
396 (u_int8_t*)request->data,
397 request->count,
398 request->timeout * 1000); // timeout in seconds
399
400 // ata_28bit_cmd
cfbba5b9
GI
401 if (request->flags == ATA_CMD_CONTROL)
402 ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT;
403 else
404 ccb.ataio.cmd.flags = 0;
eb07ddf2
GI
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;
412
413 ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
414
415 if (cam_send_ccb(m_camdev, &ccb) < 0) {
416 err(1, "cam_send_ccb");
417 return -1;
418 }
419
cfbba5b9
GI
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);
422 return -1;
423 }
eb07ddf2 424
cfbba5b9
GI
425 request->u.ata.count = ccb.ataio.res.sector_count;
426 return 0;
eb07ddf2
GI
427}
428
429#endif
430
2127e193
GI
431/////////////////////////////////////////////////////////////////////////////
432/// Implement AMCC/3ware RAID support with old functions
433
434class freebsd_escalade_device
435: public /*implements*/ ata_device_with_command_set,
436 public /*extends*/ freebsd_smart_device
437{
438public:
439 freebsd_escalade_device(smart_interface * intf, const char * dev_name,
440 int escalade_type, int disknum);
441
442protected:
443 virtual int ata_command_interface(smart_command_set command, int select, char * data);
eb07ddf2 444 virtual bool open();
2127e193
GI
445
446private:
447 int m_escalade_type; ///< Type string for escalade_command_interface().
448 int m_disknum; ///< Disk number.
449};
450
451freebsd_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)
459{
460 set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
461}
462
eb07ddf2
GI
463bool freebsd_escalade_device::open()
464{
465 const char *dev = get_dev_name();
466 int fd;
467
468 if ((fd = ::open(dev,O_RDWR))<0) {
469 set_err(errno);
470 return false;
471 }
472 set_fd(fd);
473 return true;
474}
475
2127e193
GI
476int freebsd_escalade_device::ata_command_interface(smart_command_set command, int select, char * data)
477{
54965743
GI
478 // to hold true file descriptor
479 int fd = get_fd();
2127e193
GI
480
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;
486
487 // Used by both the SCSI and char interfaces
488 char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
489
490 if (m_disknum < 0) {
491 printwarning(NO_DISK_3WARE,NULL);
492 return -1;
493 }
494
2127e193
GI
495 memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
496
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;
505 } else {
506 pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
54965743 507 "Please contact " PACKAGE_BUGREPORT "\n", m_escalade_type, m_disknum);
2127e193
GI
508 errno=ENOSYS;
509 return -1;
510 }
511
512 ata->opcode = TWE_OP_ATA_PASSTHROUGH;
513
514 // Same for (almost) all commands - but some reset below
515 ata->request_id = 0xFF;
516 ata->unit = m_disknum;
517 ata->status = 0;
518 ata->flags = 0x1;
519 ata->drive_head = 0x0;
520 ata->sector_num = 0;
521
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;
54965743 526
2127e193
GI
527 // SMART ATA COMMAND REGISTER value
528 ata->command = ATA_SMART_CMD;
54965743 529
2127e193
GI
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 ||
54965743
GI
541 command == WRITE_LOG )
542 {
2127e193
GI
543 readdata=1;
544 if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
545 cmd_twe->tu_data = data;
546 cmd_twe->tu_size = 512;
547 }
548 ata->sgl_offset = 0x5;
549 ata->size = 0x5;
550 ata->param = 0xD;
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)
557 // ata->size++;
558 }
559 else {
560 // Non data command -- but doesn't use large sector
561 // count register values.
562 ata->sgl_offset = 0x0;
563 ata->size = 0x5;
564 ata->param = 0x8;
565 ata->sector_count = 0x0;
566 }
54965743 567
2127e193
GI
568 // Now set ATA registers depending upon command
569 switch (command){
570 case CHECK_POWER_MODE:
571 ata->command = ATA_CHECK_POWER_MODE;
572 ata->features = 0;
573 ata->cylinder_lo = 0;
574 ata->cylinder_hi = 0;
575 break;
576 case READ_VALUES:
577 ata->features = ATA_SMART_READ_VALUES;
578 break;
579 case READ_THRESHOLDS:
580 ata->features = ATA_SMART_READ_THRESHOLDS;
581 break;
582 case READ_LOG:
583 ata->features = ATA_SMART_READ_LOG_SECTOR;
584 // log number to return
585 ata->sector_num = select;
586 break;
587 case WRITE_LOG:
588 readdata=0;
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
593 break;
594 case IDENTIFY:
595 // ATA IDENTIFY DEVICE
596 ata->command = ATA_IDENTIFY_DEVICE;
597 ata->features = 0;
598 ata->cylinder_lo = 0;
599 ata->cylinder_hi = 0;
600 break;
601 case PIDENTIFY:
602 // 3WARE controller can NOT have packet device internally
603 pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum);
604 errno=ENODEV;
605 return -1;
606 case ENABLE:
607 ata->features = ATA_SMART_ENABLE;
608 break;
609 case DISABLE:
610 ata->features = ATA_SMART_DISABLE;
611 break;
612 case AUTO_OFFLINE:
613 ata->features = ATA_SMART_AUTO_OFFLINE;
614 // Enable or disable?
615 ata->sector_count = select;
616 break;
617 case AUTOSAVE:
618 ata->features = ATA_SMART_AUTOSAVE;
619 // Enable or disable?
620 ata->sector_count = select;
621 break;
622 case IMMEDIATE_OFFLINE:
623 ata->features = ATA_SMART_IMMEDIATE_OFFLINE;
624 // What test type to run?
625 ata->sector_num = select;
626 break;
627 case STATUS_CHECK:
628 ata->features = ATA_SMART_STATUS;
629 break;
630 case 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;
635 break;
636 default:
637 pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
638 "Please contact " PACKAGE_BUGREPORT "\n", command, m_disknum);
639 errno=ENOSYS;
640 return -1;
641 }
642
643 // Now send the command down through an ioctl()
644 if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
eb07ddf2 645 ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
2127e193 646 } else {
eb07ddf2 647 ioctlreturn=ioctl(fd,TWEIO_COMMAND,cmd_twe);
2127e193
GI
648 }
649
650 // Deal with the different error cases
651 if (ioctlreturn) {
652 if (!errno)
653 errno=EIO;
654 return -1;
655 }
54965743 656
2127e193
GI
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
662 //
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
667 // happened.
54965743 668
2127e193
GI
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);
671 errno=EIO;
672 return -1;
673 }
54965743 674
2127e193
GI
675 // If this is a read data command, copy data to output buffer
676 if (readdata) {
677 if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR)
678 memcpy(data, cmd_twa->pdata, 512);
679 }
680
681 // For STATUS_CHECK, we need to check register values
682 if (command==STATUS_CHECK) {
54965743 683
2127e193
GI
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
686 // High Registers.
54965743 687
2127e193
GI
688 unsigned short cyl_lo=ata->cylinder_lo;
689 unsigned short cyl_hi=ata->cylinder_hi;
54965743 690
2127e193
GI
691 // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
692 if (cyl_lo==0x4F && cyl_hi==0xC2)
693 return 0;
54965743 694
2127e193
GI
695 // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
696 if (cyl_lo==0xF4 && cyl_hi==0x2C)
697 return 1;
54965743 698
2127e193
GI
699 errno=EIO;
700 return -1;
701 }
54965743 702
2127e193
GI
703 // copy sector count register (one byte!) to return data
704 if (command==CHECK_POWER_MODE)
705 *data=*(char *)&(ata->sector_count);
54965743 706
2127e193 707 // look for nonexistent devices/ports
a23d5117 708 if (command==IDENTIFY && !nonempty(data, 512)) {
2127e193
GI
709 errno=ENODEV;
710 return -1;
711 }
54965743 712
2127e193
GI
713 return 0;
714}
715
716
717/////////////////////////////////////////////////////////////////////////////
718/// Implement Highpoint RAID support with old functions
719
720class freebsd_highpoint_device
721: public /*implements*/ ata_device_with_command_set,
722 public /*extends*/ freebsd_smart_device
723{
724public:
725 freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
726 unsigned char controller, unsigned char channel, unsigned char port);
727
728protected:
729 virtual int ata_command_interface(smart_command_set command, int select, char * data);
eb07ddf2 730 virtual bool open();
2127e193
GI
731
732private:
733 unsigned char m_hpt_data[3]; ///< controller/channel/port
734};
735
736
737freebsd_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")
741{
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]);
744}
745
eb07ddf2
GI
746bool freebsd_highpoint_device::open()
747{
748 const char *dev = get_dev_name();
749 int fd;
750
751 if ((fd = ::open(dev,O_RDWR))<0) {
752 set_err(errno);
753 return false;
754 }
755 set_fd(fd);
756 return true;
757}
758
2127e193
GI
759int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
760{
54965743 761 int fd=get_fd();
2127e193 762 int ids[2];
2127e193
GI
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;
767
2127e193
GI
768 // get internal deviceid
769 ids[0] = m_hpt_data[0] - 1;
770 ids[1] = m_hpt_data[1] - 1;
771
772 memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
773
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);
780
781 if (m_hpt_data[2]==1) {
782 param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO;
783 param.out_size = sizeof(HPT_CHANNEL_INFO);
784 }
eb07ddf2 785 if (ioctl(fd, HPT_DO_IOCONTROL, &param)!=0 ||
2127e193
GI
786 info.devices[m_hpt_data[2]-1]==0) {
787 return -1;
788 }
789
790 // perform smart action
791 memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER));
792 pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff;
793
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];
798
799 switch (command){
800 case READ_VALUES:
801 pide_pt_hdr->feature=ATA_SMART_READ_VALUES;
802 pide_pt_hdr->protocol=HPT_READ;
803 break;
804 case READ_THRESHOLDS:
805 pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS;
806 pide_pt_hdr->protocol=HPT_READ;
807 break;
808 case READ_LOG:
809 pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR;
810 pide_pt_hdr->lbalow=select;
811 pide_pt_hdr->protocol=HPT_READ;
812 break;
813 case IDENTIFY:
814 pide_pt_hdr->command=ATA_IDENTIFY_DEVICE;
815 pide_pt_hdr->protocol=HPT_READ;
816 break;
817 case ENABLE:
818 pide_pt_hdr->feature=ATA_SMART_ENABLE;
819 break;
820 case DISABLE:
821 pide_pt_hdr->feature=ATA_SMART_DISABLE;
822 break;
823 case AUTO_OFFLINE:
824 pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE;
825 pide_pt_hdr->sectorcount=select;
826 break;
827 case AUTOSAVE:
828 pide_pt_hdr->feature=ATA_SMART_AUTOSAVE;
829 pide_pt_hdr->sectorcount=select;
830 break;
831 case IMMEDIATE_OFFLINE:
832 pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE;
833 pide_pt_hdr->lbalow=select;
834 break;
835 case STATUS_CHECK:
836 case STATUS:
837 pide_pt_hdr->feature=ATA_SMART_STATUS;
838 break;
839 case CHECK_POWER_MODE:
840 pide_pt_hdr->command=ATA_CHECK_POWER_MODE;
841 break;
842 case WRITE_LOG:
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;
847 break;
848 default:
849 pout("Unrecognized command %d in highpoint_command_interface()\n"
850 "Please contact " PACKAGE_BUGREPORT "\n", command);
851 errno=ENOSYS;
852 return -1;
853 }
854 if (pide_pt_hdr->protocol!=0) {
855 pide_pt_hdr->sectors = 1;
856 pide_pt_hdr->sectorcount = 1;
857 }
858
859 memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
860
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);
867
868 pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out;
869
eb07ddf2 870 if ((ioctl(fd, HPT_DO_IOCONTROL, &param)!=0) ||
2127e193
GI
871 (pide_pt_hdr_out->command & 1)) {
872 return -1;
873 }
874
54965743
GI
875 if (command==STATUS_CHECK)
876 {
2127e193
GI
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;
880
881 high = pide_pt_hdr_out->lbahigh;
882 low = pide_pt_hdr_out->lbamid;
883
884 // Cyl low and Cyl high unchanged means "Good SMART status"
885 if (low==normal_lo && high==normal_hi)
886 return 0;
887
888 // These values mean "Bad SMART status"
889 if (low==failed_lo && high==failed_hi)
890 return 1;
891
892 // We haven't gotten output that makes sense; print out some debugging info
893 char buf[512];
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);
903 }
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)
54965743
GI
907 memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER),
908 pide_pt_hdr->sectors * 512);
2127e193
GI
909 return 0;
910}
911
912
913/////////////////////////////////////////////////////////////////////////////
914/// Implement standard SCSI support with old functions
915
916class freebsd_scsi_device
917: public /*implements*/ scsi_device,
918 public /*extends*/ freebsd_smart_device
919{
920public:
921 freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
922
923 virtual smart_device * autodetect_open();
924
925 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
eb07ddf2
GI
926
927 virtual bool open();
928
929 virtual bool close();
930
931private:
932 int m_fd;
933 struct cam_device *m_camdev;
2127e193
GI
934};
935
eb07ddf2
GI
936bool freebsd_scsi_device::open(){
937 const char *dev = get_dev_name();
938
939 if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
940 set_err(errno);
941 return false;
942 }
943 set_fd(m_camdev->fd);
944 return true;
945}
946
947bool freebsd_scsi_device::close(){
948 cam_close_device(m_camdev);
949 set_fd(-1);
950 return true;
951}
952
2127e193
GI
953freebsd_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")
957{
958}
959
eb07ddf2
GI
960
961bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
2127e193 962{
cfbba5b9 963 int report=scsi_debugmode;
2127e193 964 union ccb *ccb;
54965743
GI
965
966 if (report > 0) {
967 unsigned int k;
968 const unsigned char * ucp = iop->cmnd;
969 const char * np;
970
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]);
975 if ((report > 1) &&
976 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
977 int trunc = (iop->dxfer_len > 256) ? 1 : 0;
978
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);
982 }
983 else
984 pout("]");
985 }
2127e193 986
eb07ddf2
GI
987 if(m_camdev==NULL) {
988 warnx("error: camdev=0!");
54965743 989 return -ENOTTY;
2127e193
GI
990 }
991
eb07ddf2 992 if (!(ccb = cam_getccb(m_camdev))) {
2127e193
GI
993 warnx("error allocating ccb");
994 return -ENOMEM;
995 }
996
997 // clear out structure, except for header that was filled in for us
998 bzero(&(&ccb->ccb_h)[1],
54965743 999 sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
2127e193
GI
1000
1001 cam_fill_csio(&ccb->csio,
54965743
GI
1002 /*retrires*/ 1,
1003 /*cbfcnp*/ NULL,
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);
2127e193
GI
1011 memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len);
1012
eb07ddf2 1013 if (cam_send_ccb(m_camdev,ccb) < 0) {
2127e193 1014 warn("error sending SCSI ccb");
54965743 1015#if (FREEBSDVER > 500000)
eb07ddf2 1016 cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
54965743 1017#endif
2127e193
GI
1018 cam_freeccb(ccb);
1019 return -EIO;
1020 }
1021
54965743
GI
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)
eb07ddf2 1024 cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
54965743 1025#endif
2127e193
GI
1026 cam_freeccb(ccb);
1027 return -EIO;
1028 }
1029
1030 if (iop->sensep) {
1031 memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data));
1032 iop->resp_sense_len = sizeof(struct scsi_sense_data);
1033 }
1034
1035 iop->scsi_status = ccb->csio.scsi_status;
1036
1037 cam_freeccb(ccb);
54965743 1038
2127e193
GI
1039 if (report > 0) {
1040 int trunc;
1041
1042 pout(" status=0\n");
1043 trunc = (iop->dxfer_len > 256) ? 1 : 0;
54965743 1044
2127e193 1045 pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
54965743 1046 (trunc ? " [only first 256 bytes shown]" : ""));
2127e193
GI
1047 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
1048 }
54965743 1049
2127e193
GI
1050 return true;
1051}
1052
1053
1054/////////////////////////////////////////////////////////////////////////////
1055/// Implement CCISS RAID support with old functions
1056
1057class freebsd_cciss_device
1058: public /*implements*/ scsi_device,
1059 public /*extends*/ freebsd_smart_device
1060{
1061public:
1062 freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
1063
1064 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
eb07ddf2 1065 virtual bool open();
2127e193
GI
1066
1067private:
1068 unsigned char m_disknum; ///< Disk number.
1069};
1070
eb07ddf2
GI
1071bool freebsd_cciss_device::open()
1072{
1073 const char *dev = get_dev_name();
1074 int fd;
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");
1078 return false;
1079#endif
1080 if ((fd = ::open(dev,O_RDWR))<0) {
1081 set_err(errno);
1082 return false;
1083 }
1084 set_fd(fd);
1085 return true;
1086}
2127e193
GI
1087
1088freebsd_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"),
1092 m_disknum(disknum)
1093{
1094 set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
1095}
1096
1097bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
1098{
eb07ddf2 1099#ifdef HAVE_DEV_CISS_CISSIO_H
cfbba5b9 1100 int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
eb07ddf2
GI
1101 if (status < 0)
1102 return set_err(-status);
1103 return true;
1104#endif
1105 // not reached
2127e193
GI
1106 return true;
1107}
1108
1109
1110/////////////////////////////////////////////////////////////////////////////
1111/// SCSI open with autodetection support
1112
1113smart_device * freebsd_scsi_device::autodetect_open()
1114{
1115 // Open device
1116 if (!open())
1117 return this;
1118
1119 // No Autodetection if device type was specified by user
1120 if (*get_req_type())
1121 return this;
1122
1123 // The code below is based on smartd.cpp:SCSIFilterKnown()
1124
1125 // Get INQUIRY
1126 unsigned char req_buff[64] = {0, };
1127 int req_len = 36;
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
1131 req_len = 64;
1132 if (scsiStdInquiry(this, req_buff, req_len)) {
1133 // device doesn't like INQUIRY commands
1134 close();
1135 set_err(EIO, "INQUIRY failed");
1136 return this;
1137 }
1138 }
1139
1140 int avail_len = req_buff[4] + 5;
1141 int len = (avail_len < req_len ? avail_len : req_len);
1142 if (len < 36)
54965743 1143 return this;
2127e193
GI
1144
1145 // Use INQUIRY to detect type
2127e193 1146
bed94269
GI
1147 // 3ware ?
1148 if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
1149 close();
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());
1152 return this;
1153 }
1154
1155 // SAT or USB ?
1156 {
1157 smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
2127e193
GI
1158 if (newdev)
1159 // NOTE: 'this' is now owned by '*newdev'
1160 return newdev;
1161 }
2127e193
GI
1162
1163 // Nothing special found
1164 return this;
1165}
1166
1167
1168/////////////////////////////////////////////////////////////////////////////
1169/// Implement platform interface with old functions.
1170
1171class freebsd_smart_interface
1172: public /*implements*/ smart_interface
1173{
1174public:
54965743 1175 virtual std::string get_os_version_str();
2127e193 1176
54965743 1177 virtual std::string get_app_examples(const char * appname);
2127e193
GI
1178
1179 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
1180 const char * pattern = 0);
1181
1182protected:
1183 virtual ata_device * get_ata_device(const char * name, const char * type);
1184
eb07ddf2
GI
1185#if FREEBSDVER > 800100
1186 virtual ata_device * get_atacam_device(const char * name, const char * type);
1187#endif
1188
2127e193
GI
1189 virtual scsi_device * get_scsi_device(const char * name, const char * type);
1190
1191 virtual smart_device * autodetect_smart_device(const char * name);
1192
1193 virtual smart_device * get_custom_smart_device(const char * name, const char * type);
1194
54965743 1195 virtual std::string get_valid_custom_dev_types_str();
2127e193
GI
1196};
1197
1198
1199//////////////////////////////////////////////////////////////////////
54965743
GI
1200
1201std::string freebsd_smart_interface::get_os_version_str()
2127e193 1202{
54965743
GI
1203 struct utsname osname;
1204 uname(&osname);
1205 return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
2127e193
GI
1206}
1207
54965743 1208std::string freebsd_smart_interface::get_app_examples(const char * appname)
2127e193
GI
1209{
1210 if (!strcmp(appname, "smartctl"))
1211 return smartctl_examples;
54965743 1212 return "";
2127e193
GI
1213}
1214
1215ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
1216{
1217 return new freebsd_ata_device(this, name, type);
1218}
1219
eb07ddf2
GI
1220#if FREEBSDVER > 800100
1221ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type)
2127e193 1222{
eb07ddf2 1223 return new freebsd_atacam_device(this, name, type);
2127e193 1224}
eb07ddf2 1225#endif
832b75ed 1226
eb07ddf2
GI
1227scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
1228{
1229 return new freebsd_scsi_device(this, name, type);
832b75ed
GG
1230}
1231
54965743
GI
1232// we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
1233// devices on system despite of it's names
2127e193
GI
1234//
1235// If any errors occur, leave errno set as it was returned by the
1236// system call, and return <0.
1237//
eb07ddf2
GI
1238// arguments:
1239// names: resulting array
1240// show_all - export duplicate device name or not
1241//
2127e193
GI
1242// Return values:
1243// -1: error
1244// >=0: number of discovered devices
832b75ed 1245
cfbba5b9
GI
1246bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
1247{
1248 int fd;
2127e193
GI
1249 if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
1250 if (errno == ENOENT) /* There are no CAM device on this computer */
1251 return 0;
cfbba5b9 1252 int serrno = errno;
2127e193 1253 pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
cfbba5b9
GI
1254 errno = serrno;
1255 return false;
832b75ed 1256 }
2127e193 1257
cfbba5b9 1258 union ccb ccb;
2127e193
GI
1259 bzero(&ccb, sizeof(union ccb));
1260
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;
1264
1265 ccb.ccb_h.func_code = XPT_DEV_MATCH;
cfbba5b9 1266 int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
2127e193 1267 ccb.cdm.match_buf_len = bufsize;
cfbba5b9 1268 // TODO: Use local buffer instead of malloc() if possible
2127e193
GI
1269 ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
1270 if (ccb.cdm.matches == NULL) {
cfbba5b9
GI
1271 close(fd);
1272 throw std::bad_alloc();
2127e193
GI
1273 }
1274 ccb.cdm.num_matches = 0;
2127e193
GI
1275 ccb.cdm.num_patterns = 0;
1276 ccb.cdm.pattern_buf_len = 0;
1277
1278 /*
1279 * We do the ioctl multiple times if necessary, in case there are
1280 * more than MAX_NUM_DEV nodes in the EDT.
1281 */
cfbba5b9
GI
1282 int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool
1283 std::string devname;
2127e193
GI
1284 do {
1285 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
cfbba5b9 1286 int serrno = errno;
2127e193 1287 pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
cfbba5b9
GI
1288 free(ccb.cdm.matches);
1289 close(fd);
1290 errno = serrno;
1291 return false;
832b75ed 1292 }
2127e193
GI
1293
1294 if ((ccb.ccb_h.status != CAM_REQ_CMP)
54965743
GI
1295 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
1296 && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
2127e193 1297 pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
cfbba5b9
GI
1298 free(ccb.cdm.matches);
1299 close(fd);
1300 errno = ENXIO;
1301 return false;
832b75ed 1302 }
2127e193 1303
cfbba5b9 1304 for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
2127e193
GI
1305 struct bus_match_result *bus_result;
1306 struct device_match_result *dev_result;
1307 struct periph_match_result *periph_result;
1308
1309 if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
1310 bus_result = &ccb.cdm.matches[i].result.bus_result;
1311
1312 if (strcmp(bus_result->dev_name,"ata") == 0 /* ATAPICAM devices will be probed as ATA devices, skip'em there */
54965743
GI
1313 || strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
1314 skip_bus = 1;
2127e193
GI
1315 else
1316 skip_bus = 0;
1317 changed = 1;
1318 } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
1319 dev_result = &ccb.cdm.matches[i].result.device_result;
1320
1321 if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
1322 skip_device = 1;
1323 else
1324 skip_device = 0;
eb07ddf2 1325
54965743
GI
1326 // /* Shall we skip non T_DIRECT devices ? */
1327 // if (dev_result->inq_data.device != T_DIRECT)
1328 // skip_device = 1;
2127e193 1329 changed = 1;
eb07ddf2
GI
1330 } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH &&
1331 (skip_device == 0 || show_all)) {
2127e193 1332 /* One device may be populated as many peripherals (pass0 & da0 for example).
54965743 1333 * We are searching for latest name
2127e193
GI
1334 */
1335 periph_result = &ccb.cdm.matches[i].result.periph_result;
cfbba5b9 1336 devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
2127e193
GI
1337 changed = 0;
1338 };
cfbba5b9
GI
1339 if ((changed == 1 || show_all) && !devname.empty()) {
1340 names.push_back(devname);
1341 devname.erase();
2127e193
GI
1342 changed = 0;
1343 };
1344 }
1345
cfbba5b9 1346 } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
2127e193 1347
cfbba5b9
GI
1348 if (!devname.empty())
1349 names.push_back(devname);
2127e193 1350
2127e193 1351 free(ccb.cdm.matches);
cfbba5b9
GI
1352 close(fd);
1353 return true;
832b75ed 1354}
832b75ed 1355
2127e193
GI
1356// we are using ATA subsystem enumerator to found all ATA devices on system
1357// despite of it's names
1358//
1359// If any errors occur, leave errno set as it was returned by the
1360// system call, and return <0.
832b75ed 1361
2127e193
GI
1362// Return values:
1363// -1: error
1364// >=0: number of discovered devices
1365int get_dev_names_ata(char*** names) {
1366 struct ata_ioc_devices devices;
1367 int fd=-1,maxchannel,serrno=-1,n=0;
1368 char **mp = NULL;
1369
1370 *names=NULL;
1371
1372 if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
1373 if (errno == ENOENT) /* There are no ATA device on this computer */
1374 return 0;
1375 serrno = errno;
1376 pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
1377 n = -1;
1378 goto end;
1379 };
54965743 1380
2127e193
GI
1381 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
1382 serrno = errno;
1383 pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
1384 n = -1;
1385 goto end;
1386 };
1387
1388 // allocate space for up to MAX_NUM_DEV number of ATA devices
1389 mp = (char **)calloc(MAX_NUM_DEV, sizeof(char*));
1390 if (mp == NULL) {
1391 serrno=errno;
1392 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
1393 n = -1;
1394 goto end;
1395 };
1396
1397 for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
1398 int j;
54965743 1399
2127e193
GI
1400 if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
1401 if (errno == ENXIO)
1402 continue; /* such channel not exist */
1403 pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
1404 n = -1;
1405 goto end;
1406 };
1407 for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
1408 if (devices.name[j][0] != '\0') {
1409 asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
1410 if (mp[n] == NULL) {
1411 pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
1412 n = -1;
1413 goto end;
1414 };
1415 bytes+=1+strlen(mp[n]);
1416 n++;
1417 };
1418 };
1419 };
1420 mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
f4ebf3d1
GI
1421 if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL
1422 serrno=errno;
1423 pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
1424 n = -1;
1425 goto end;
1426 };
2127e193 1427 bytes += (n)*(sizeof(char*)); // and set allocated byte count
54965743 1428
2127e193
GI
1429end:
1430 if (fd>=0)
1431 close(fd);
1432 if (n <= 0) {
1433 free(mp);
1434 mp = NULL;
832b75ed 1435 }
832b75ed 1436
2127e193 1437 *names=mp;
832b75ed 1438
2127e193
GI
1439 if (serrno>-1)
1440 errno=serrno;
1441 return n;
1442}
832b75ed 1443
2127e193
GI
1444
1445
1446bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
1447 const char * type, const char * pattern /*= 0*/)
1448{
1449 if (pattern) {
1450 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
1451 return false;
832b75ed
GG
1452 }
1453
2127e193
GI
1454 // Make namelists
1455 char * * atanames = 0; int numata = 0;
1456 if (!type || !strcmp(type, "ata")) {
1457 numata = get_dev_names_ata(&atanames);
1458 if (numata < 0) {
1459 set_err(ENOMEM);
1460 return false;
832b75ed 1461 }
2127e193
GI
1462 }
1463
cfbba5b9 1464 std::vector<std::string> scsinames;
eb07ddf2 1465 if (!type || !strcmp(type, "scsi")) { // do not export duplicated names
cfbba5b9
GI
1466 if (!get_dev_names_cam(scsinames, false)) {
1467 set_err(errno);
2127e193 1468 return false;
832b75ed 1469 }
832b75ed
GG
1470 }
1471
2127e193
GI
1472 // Add to devlist
1473 int i;
1474 if (type==NULL)
1475 type="";
1476 for (i = 0; i < numata; i++) {
1477 ata_device * atadev = get_ata_device(atanames[i], type);
1478 if (atadev)
bed94269 1479 devlist.push_back(atadev);
2127e193 1480 }
832b75ed 1481
cfbba5b9 1482 for (i = 0; i < (int)scsinames.size(); i++) {
54965743 1483 if(!*type) { // try USB autodetection if no type specified
cfbba5b9 1484 smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str());
54965743 1485 if(smartdev)
bed94269 1486 devlist.push_back(smartdev);
54965743
GI
1487 }
1488 else {
cfbba5b9 1489 scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type);
54965743 1490 if (scsidev)
bed94269 1491 devlist.push_back(scsidev);
54965743 1492 }
832b75ed 1493 }
2127e193 1494 return true;
832b75ed
GG
1495}
1496
2127e193 1497
54965743 1498#if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
2127e193 1499static char done[USB_MAX_DEVICES];
2127e193
GI
1500
1501static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
54965743
GI
1502 unsigned short & product_id, unsigned short & version)
1503{
832b75ed 1504
54965743
GI
1505 struct usb_device_info di;
1506 int e, p, i;
1507 char devname[256];
832b75ed 1508
54965743
GI
1509 snprintf(devname, sizeof(devname),"umass%d",busno);
1510
1511 di.udi_addr = a;
1512 e = ioctl(f, USB_DEVICEINFO, &di);
1513 if (e) {
1514 if (errno != ENXIO)
1515 printf("addr %d: I/O error\n", a);
1516 return 0;
1517 }
1518 done[a] = 1;
1519
1520 // list devices
1521 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
1522 if (di.udi_devnames[i][0]) {
1523 if(strcmp(di.udi_devnames[i],devname)==0) {
1524 // device found!
1525 vendor_id = di.udi_vendorNo;
1526 product_id = di.udi_productNo;
1527 version = di.udi_releaseNo;
1528 return 1;
1529 // FIXME
1530 }
1531 }
1532 }
1533 if (!rec)
1534 return 0;
1535 for (p = 0; p < di.udi_nports; p++) {
1536 int s = di.udi_ports[p];
1537 if (s >= USB_MAX_DEVICES) {
1538 continue;
1539 }
1540 if (s == 0)
1541 printf("addr 0 should never happen!\n");
1542 else {
1543 if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
1544 }
1545 }
1546 return 0;
1547}
1548#endif
832b75ed 1549
832b75ed 1550
2127e193 1551static int usbdevlist(int busno,unsigned short & vendor_id,
54965743 1552 unsigned short & product_id, unsigned short & version)
2127e193 1553{
54965743
GI
1554#if (FREEBSDVER >= 800000) // libusb2 interface
1555 struct libusb20_device *pdev = NULL;
1556 struct libusb20_backend *pbe;
1557 uint32_t matches = 0;
1558 char buf[128]; // do not change!
1559 char devname[128];
1560 uint8_t n;
1561 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
1562
1563 pbe = libusb20_be_alloc_default();
1564
1565 while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
1566 matches++;
1567
1568 if (libusb20_dev_open(pdev, 0)) {
1569 warnx("libusb20_dev_open: could not open device");
1570 return 0;
2127e193 1571 }
54965743
GI
1572
1573 pdesc=libusb20_dev_get_device_desc(pdev);
1574
1575 snprintf(devname, sizeof(devname),"umass%d:",busno);
1576 for (n = 0; n != 255; n++) {
1577 if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
1578 break;
1579 if (buf[0] == 0)
1580 continue;
1581 if(strncmp(buf,devname,strlen(devname))==0){
1582 // found!
1583 vendor_id = pdesc->idVendor;
1584 product_id = pdesc->idProduct;
1585 version = pdesc->bcdDevice;
1586 libusb20_dev_close(pdev);
1587 libusb20_be_free(pbe);
1588 return 1;
1589 }
1590 }
1591
1592 libusb20_dev_close(pdev);
1593 }
1594
1595 if (matches == 0) {
1596 printf("No device match or lack of permissions.\n");
1597 }
1598
1599 libusb20_be_free(pbe);
1600
1601 return false;
1602#else // freebsd < 8.0 USB stack, ioctl interface
1603
1604 int i, f, a, rc;
1605 char buf[50];
1606 int ncont;
1607
1608 for (ncont = 0, i = 0; i < 10; i++) {
1609 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
1610 f = open(buf, O_RDONLY);
1611 if (f >= 0) {
1612 memset(done, 0, sizeof done);
1613 for (a = 1; a < USB_MAX_DEVICES; a++) {
1614 if (!done[a]) {
1615 rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
1616 if(rc) return 1;
1617 }
1618
1619 }
1620 close(f);
1621 } else {
1622 if (errno == ENOENT || errno == ENXIO)
1623 continue;
1624 warn("%s", buf);
1625 }
1626 ncont++;
1627 }
1628 return 0;
1629#endif
2127e193
GI
1630}
1631
2127e193
GI
1632smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
1633{
2127e193 1634 unsigned short vendor_id = 0, product_id = 0, version = 0;
eb07ddf2
GI
1635 struct cam_device *cam_dev;
1636 union ccb ccb;
1637 int bus=-1;
1638 int i;
1639 int len;
54965743 1640
eb07ddf2
GI
1641 // if dev_name null, or string length zero
1642 if (!name || !(len = strlen(name)))
1643 return false;
1644
1645 // check ATA bus
1646 char * * atanames = 0; int numata = 0;
1647 numata = get_dev_names_ata(&atanames);
1648 if (numata > 0) {
1649 // check ATA/ATAPI devices
1650 for (i = 0; i < numata; i++) {
1651 if(!strcmp(atanames[i],name)) {
1652 return new freebsd_ata_device(this, name, "");
1653 }
832b75ed 1654 }
832b75ed 1655 }
eb07ddf2
GI
1656 else {
1657 if (numata < 0)
1658 pout("Unable to get ATA device list\n");
1659 }
1660
1661 // check CAM
cfbba5b9
GI
1662 std::vector<std::string> scsinames;
1663 if (!get_dev_names_cam(scsinames, true))
1664 pout("Unable to get CAM device list\n");
1665 else if (!scsinames.empty()) {
eb07ddf2 1666 // check all devices on CAM bus
cfbba5b9
GI
1667 for (i = 0; i < (int)scsinames.size(); i++) {
1668 if(strcmp(scsinames[i].c_str(), name)==0)
eb07ddf2
GI
1669 { // our disk device is CAM
1670 if ((cam_dev = cam_open_device(name, O_RDWR)) == NULL) {
1671 // open failure
1672 set_err(errno);
1673 return false;
1674 }
1675
1676 // zero the payload
1677 bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE);
1678 ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device
1679 if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
1680 warn("Get Transfer Settings CCB failed\n"
1681 "%s", strerror(errno));
1682 cam_close_device(cam_dev);
1683 return 0;
1684 }
1685 // now check if we are working with USB device, see umass.c
1686 if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found
1687 usbdevlist(bus,vendor_id, product_id, version);
1688 int bus=ccb.cpi.unit_number; // unit_number will match umass number
1689 cam_close_device(cam_dev);
1690 if(usbdevlist(bus,vendor_id, product_id, version)){
1691 const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
f4ebf3d1
GI
1692 if (usbtype)
1693 return get_sat_device(usbtype, new freebsd_scsi_device(this, name, ""));
eb07ddf2 1694 }
f4ebf3d1 1695 return false;
eb07ddf2
GI
1696 }
1697#if FREEBSDVER > 800100
1698 // check if we have ATA device connected to CAM (ada)
1699 if(ccb.cpi.protocol == PROTO_ATA){
1700 cam_close_device(cam_dev);
1701 return new freebsd_atacam_device(this, name, "");
1702 }
1703#endif
1704 // close cam device, we don`t need it anymore
1705 cam_close_device(cam_dev);
1706 // handle as usual scsi
1707 return new freebsd_scsi_device(this, name, "");
1708 }
1709 }
eb07ddf2
GI
1710 }
1711 // device type unknown
2127e193
GI
1712 return 0;
1713}
1714
1715
1716smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
1717{
1718 // 3Ware ?
eb07ddf2
GI
1719 static const char * fbsd_dev_twe_ctrl = "/dev/twe";
1720 static const char * fbsd_dev_twa_ctrl = "/dev/twa";
1721 int disknum = -1, n1 = -1, n2 = -1, contr = -1;
1722
2127e193
GI
1723 if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
1724 if (n2 != (int)strlen(type)) {
1725 set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
1726 return 0;
1727 }
1728 if (!(0 <= disknum && disknum <= 127)) {
1729 set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
1730 return 0;
1731 }
eb07ddf2
GI
1732
1733 // guess 3ware device type based on device name
1734 if (!strncmp(fbsd_dev_twa_ctrl, name, strlen(fbsd_dev_twa_ctrl))){
1735 contr=CONTROLLER_3WARE_9000_CHAR;
1736 }
1737 if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){
1738 contr=CONTROLLER_3WARE_678K_CHAR;
1739 }
1740
1741 if(contr == -1){
1742 set_err(EINVAL, "3ware controller type unknown, use %sX or %sX devices",
1743 fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl);
1744 return 0;
1745 }
54965743 1746 return new freebsd_escalade_device(this, name, contr, disknum);
2127e193
GI
1747 }
1748
1749 // Highpoint ?
1750 int controller = -1, channel = -1; disknum = 1;
1751 n1 = n2 = -1; int n3 = -1;
1752 if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
1753 int len = strlen(type);
1754 if (!(n2 == len || n3 == len)) {
1755 set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
1756 return 0;
1757 }
1758 if (!(1 <= controller && controller <= 8)) {
1759 set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
1760 return 0;
1761 }
1762 if (!(1 <= channel && channel <= 8)) {
1763 set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
1764 return 0;
1765 }
1766 if (!(1 <= disknum && disknum <= 15)) {
1767 set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
1768 return 0;
1769 }
1770 return new freebsd_highpoint_device(this, name, controller, channel, disknum);
832b75ed
GG
1771 }
1772
2127e193
GI
1773 // CCISS ?
1774 disknum = n1 = n2 = -1;
1775 if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
1776 if (n2 != (int)strlen(type)) {
1777 set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
1778 return 0;
1779 }
e9583e0c
GI
1780 if (!(0 <= disknum && disknum <= 127)) {
1781 set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
2127e193
GI
1782 return 0;
1783 }
1784 return new freebsd_cciss_device(this, name, disknum);
832b75ed 1785 }
eb07ddf2
GI
1786#if FREEBSDVER > 800100
1787 // adaX devices ?
1788 if(!strcmp(type,"atacam"))
1789 return new freebsd_atacam_device(this, name, "");
1790#endif
832b75ed 1791
2127e193 1792 return 0;
832b75ed
GG
1793}
1794
54965743 1795std::string freebsd_smart_interface::get_valid_custom_dev_types_str()
2127e193 1796{
eb07ddf2
GI
1797 return "3ware,N, hpt,L/M/N, cciss,N"
1798#if FREEBSDVER > 800100
1799 ", atacam"
1800#endif
1801 ;
2127e193
GI
1802}
1803
2127e193
GI
1804} // namespace
1805
2127e193
GI
1806/////////////////////////////////////////////////////////////////////////////
1807/// Initialize platform interface and register with smi()
1808
1809void smart_interface::init()
1810{
1811 static os_freebsd::freebsd_smart_interface the_interface;
1812 smart_interface::set(&the_interface);
832b75ed 1813}