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