1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

root/trunk/smartmontools/os_freebsd.cpp @ 3654

Revision 3654, 56.1 KB (checked in by samm2, 7 months ago)

os_freebsd.cpp: fix error in previous commit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * os_freebsd.c
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net>
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 <errno.h>
24#include <camlib.h>
25#include <cam/scsi/scsi_message.h>
26#include <cam/scsi/scsi_pass.h>
27#if defined(__DragonFly__)
28#include <sys/nata.h>
29#else
30#include <sys/ata.h>
31#endif
32#include <sys/stat.h>
33#include <unistd.h>
34#include <glob.h>
35#include <stddef.h>
36#include <paths.h>
37#include <sys/utsname.h>
38
39#include "config.h"
40#include "int64.h"
41#include "atacmds.h"
42#include "scsicmds.h"
43#include "cciss.h"
44#include "utility.h"
45#include "os_freebsd.h"
46
47#include "dev_interface.h"
48#include "dev_ata_cmd_set.h"
49#include "dev_areca.h"
50
51#define USBDEV "/dev/usb"
52#if defined(__FreeBSD_version)
53
54// This way we define one variable for the GNU/kFreeBSD and FreeBSD
55#define FREEBSDVER __FreeBSD_version
56#else
57#define FREEBSDVER __FreeBSD_kernel_version
58#endif
59
60#if (FREEBSDVER >= 800000)
61#include <libusb20_desc.h>
62#include <libusb20.h>
63#elif defined(__DragonFly__)
64#include <bus/usb/usb.h>
65#include <bus/usb/usbhid.h>
66#else
67#include <dev/usb/usb.h>
68#include <dev/usb/usbhid.h>
69#endif
70
71#define CONTROLLER_3WARE_9000_CHAR      0x01
72#define CONTROLLER_3WARE_678K_CHAR      0x02
73
74#ifndef PATHINQ_SETTINGS_SIZE
75#define PATHINQ_SETTINGS_SIZE   128
76#endif
77
78const char *os_XXXX_c_cvsid="$Id$" \
79ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
80
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",
92
93    "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
94
95    "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
96
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
111// Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
112
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) )
116
117#ifndef ATA_DEVICE
118#define ATA_DEVICE "/dev/ata"
119#endif
120
121#define ARGUSED(x) ((void)(x))
122
123// global variable holding byte count of allocated memory
124long long bytes;
125
126/////////////////////////////////////////////////////////////////////////////
127
128namespace os_freebsd { // No need to publish anything, name provided for Doxygen
129
130/////////////////////////////////////////////////////////////////////////////
131/// Implement shared open/close routines with old functions.
132
133class freebsd_smart_device
134: virtual public /*implements*/ smart_device
135{
136public:
137  explicit freebsd_smart_device(const char * mode)
138    : smart_device(never_called),
139      m_fd(-1), m_mode(mode) { }
140
141  virtual ~freebsd_smart_device() throw();
142
143  virtual bool is_open() const;
144
145  virtual bool open();
146
147  virtual bool close();
148
149protected:
150  /// Return filedesc for derived classes.
151  int get_fd() const
152    { return m_fd; }
153
154  void set_fd(int fd)
155    { m_fd = fd; }
156
157private:
158  int m_fd; ///< filedesc, -1 if not open.
159  const char * m_mode; ///< Mode string for deviceopen().
160};
161
162#ifdef __GLIBC__
163static inline void * reallocf(void *ptr, size_t size) {
164   void *rv = realloc(ptr, size);
165   if((rv == NULL) && (size != 0))
166     free(ptr);
167   return rv;
168   }
169#endif
170
171freebsd_smart_device::~freebsd_smart_device() throw()
172{
173  if (m_fd >= 0)
174    os_freebsd::freebsd_smart_device::close();
175}
176
177// migration from the old_style
178unsigned char m_controller_type;
179unsigned char m_controller_port; 
180
181// examples for smartctl
182static const char  smartctl_examples[] =
183   "=================================================== SMARTCTL EXAMPLES =====\n\n"
184         "  smartctl -a /dev/ad0                       (Prints all SMART information)\n\n"
185         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
186         "                                              (Enables SMART on first disk)\n\n"
187         "  smartctl -t long /dev/ad0              (Executes extended disk self-test)\n\n"
188         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
189         "                                      (Prints Self-Test & Attribute errors)\n"
190         "                                      (Prints Self-Test & Attribute errors)\n\n"
191         "  smartctl -a --device=3ware,2 /dev/twa0\n"
192         "  smartctl -a --device=3ware,2 /dev/twe0\n"
193         "  smartctl -a --device=3ware,2 /dev/tws0\n"
194         "                              (Prints all SMART information for ATA disk on\n"
195         "                                 third port of first 3ware RAID controller)\n"
196  "  smartctl -a --device=cciss,0 /dev/ciss0\n"
197         "                              (Prints all SMART information for first disk \n"
198         "                               on Common Interface for SCSI-3 Support driver)\n"
199  "  smartctl -a --device=areca,3/1 /dev/arcmsr0\n"
200         "                              (Prints all SMART information for 3rd disk in the 1st enclosure \n"
201         "                               on first ARECA RAID controller)\n"
202
203         ;
204
205bool freebsd_smart_device::is_open() const
206{
207  return (m_fd >= 0);
208}
209
210
211bool freebsd_smart_device::open()
212{
213  const char *dev = get_dev_name();
214  if ((m_fd = ::open(dev,O_RDONLY))<0) {
215    set_err(errno);
216    return false;
217  }
218  return true;
219}
220
221bool freebsd_smart_device::close()
222{
223  int failed = 0;
224  // close device, if open
225  if (is_open())
226    failed=::close(get_fd());
227
228  set_fd(-1);
229
230  if(failed) return false;
231    else return true;
232}
233
234/////////////////////////////////////////////////////////////////////////////
235/// Implement standard ATA support
236
237class freebsd_ata_device
238: public /*implements*/ ata_device,
239  public /*extends*/ freebsd_smart_device
240{
241public:
242  freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
243  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
244
245protected:
246  virtual int do_cmd(struct ata_ioc_request* request, bool is_48bit_cmd);
247};
248
249freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
250: smart_device(intf, dev_name, "ata", req_type),
251  freebsd_smart_device("ATA")
252{
253}
254
255int freebsd_ata_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd)
256{
257  int fd = get_fd();
258  ARGUSED(is_48bit_cmd); // no support for 48 bit commands in the IOCATAREQUEST
259  return ioctl(fd, IOCATAREQUEST, request);
260}
261
262
263
264bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
265{
266  bool ata_48bit = false; // no ata_48bit_support via IOCATAREQUEST
267  if(!strcmp("atacam",get_dev_type())) // enable for atacam interface
268    ata_48bit = true;
269
270  if (!ata_cmd_is_ok(in,
271    true,  // data_out_support
272    true,  // multi_sector_support
273    ata_48bit) 
274    ) 
275    return false;
276
277  struct ata_ioc_request request;
278  bzero(&request,sizeof(struct ata_ioc_request));
279
280  request.timeout=SCSI_TIMEOUT_DEFAULT;
281  request.u.ata.command=in.in_regs.command;
282  request.u.ata.feature=in.in_regs.features;
283
284  request.u.ata.count = in.in_regs.sector_count_16;
285  request.u.ata.lba = in.in_regs.lba_48;
286
287  switch (in.direction) {
288    case ata_cmd_in::no_data: 
289      request.flags=ATA_CMD_CONTROL;
290      break;
291    case ata_cmd_in::data_in: 
292      request.flags=ATA_CMD_READ | ATA_CMD_CONTROL;
293      request.data=(char *)in.buffer;
294      request.count=in.size;
295      break;
296    case ata_cmd_in::data_out: 
297      request.flags=ATA_CMD_WRITE | ATA_CMD_CONTROL;
298      request.data=(char *)in.buffer;
299      request.count=in.size;
300      break;
301    default:
302      return set_err(ENOSYS);
303  }
304
305  clear_err();
306  errno = 0;
307  if (do_cmd(&request, in.in_regs.is_48bit_cmd()))
308      return set_err(errno);
309  if (request.error)
310      return set_err(EIO, "request failed, error code 0x%02x", request.error);
311
312  out.out_regs.error = request.error;
313  out.out_regs.sector_count_16 = request.u.ata.count;
314  out.out_regs.lba_48 = request.u.ata.lba;
315
316
317  // Command specific processing
318  if (in.in_regs.command == ATA_SMART_CMD
319       && in.in_regs.features == ATA_SMART_STATUS
320       && in.out_needed.lba_high)
321  {
322    unsigned const char normal_lo=0x4f, normal_hi=0xc2;
323    unsigned const char failed_lo=0xf4, failed_hi=0x2c;
324
325    // Cyl low and Cyl high unchanged means "Good SMART status"
326    if (!(out.out_regs.lba_mid==normal_lo && out.out_regs.lba_high==normal_hi)
327    // These values mean "Bad SMART status"
328        && !(out.out_regs.lba_mid==failed_lo && out.out_regs.lba_high==failed_hi))
329
330    {
331      // We haven't gotten output that makes sense; print out some debugging info
332      char buf[512];
333      sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
334        (int)request.u.ata.command,
335        (int)request.u.ata.feature,
336        (int)request.u.ata.count,
337        (int)((request.u.ata.lba) & 0xff),
338        (int)((request.u.ata.lba>>8) & 0xff),
339        (int)((request.u.ata.lba>>16) & 0xff),
340        (int)request.error);
341      printwarning(BAD_SMART,buf);
342      out.out_regs.lba_high = failed_hi; 
343      out.out_regs.lba_mid = failed_lo;
344    }
345  }
346
347  return true;
348}
349
350#if FREEBSDVER > 800100
351class freebsd_atacam_device : public freebsd_ata_device
352{
353public:
354  freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type)
355  : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type)
356  {}
357 
358  virtual bool open();
359  virtual bool close();
360 
361protected:
362  int m_fd;
363  struct cam_device *m_camdev;
364
365  virtual int do_cmd( struct ata_ioc_request* request , bool is_48bit_cmd);
366};
367
368bool freebsd_atacam_device::open(){
369  const char *dev = get_dev_name();
370 
371  if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
372    set_err(errno);
373    return false;
374  }
375  set_fd(m_camdev->fd);
376  return true;
377}
378
379bool freebsd_atacam_device::close(){
380  cam_close_device(m_camdev);
381  set_fd(-1);
382  return true;
383}
384
385int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd)
386{
387  union ccb ccb;
388  int camflags;
389
390  memset(&ccb, 0, sizeof(ccb));
391
392  if (request->count == 0)
393    camflags = CAM_DIR_NONE;
394  else if (request->flags & ATA_CMD_READ)
395    camflags = CAM_DIR_IN;
396  else
397    camflags = CAM_DIR_OUT;
398  if(is_48bit_cmd)
399    camflags |= CAM_ATAIO_48BIT;
400
401  cam_fill_ataio(&ccb.ataio,
402                 0,
403                 NULL,
404                 camflags,
405                 MSG_SIMPLE_Q_TAG,
406                 (u_int8_t*)request->data,
407                 request->count,
408                 request->timeout * 1000); // timeout in seconds
409
410  ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT;
411  // ata_28bit_cmd
412  ccb.ataio.cmd.command = request->u.ata.command;
413  ccb.ataio.cmd.features = request->u.ata.feature;
414  ccb.ataio.cmd.lba_low = request->u.ata.lba;
415  ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8;
416  ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16;
417  // ata_48bit cmd
418  ccb.ataio.cmd.lba_low_exp = request->u.ata.lba >> 24;
419  ccb.ataio.cmd.lba_mid_exp = request->u.ata.lba >> 32;
420  ccb.ataio.cmd.lba_high_exp = request->u.ata.lba >> 40;
421  ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f);
422  ccb.ataio.cmd.sector_count = request->u.ata.count;
423  ccb.ataio.cmd.sector_count_exp = request->u.ata.count  >> 8;;
424
425  ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
426
427  if (cam_send_ccb(m_camdev, &ccb) < 0) {
428    err(1, "cam_send_ccb");
429    return -1;
430  }
431
432  if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
433    cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
434    return -1;
435  }
436
437  request->u.ata.lba =
438    ((u_int64_t)(ccb.ataio.res.lba_low)) |
439    ((u_int64_t)(ccb.ataio.res.lba_mid) << 8) |
440    ((u_int64_t)(ccb.ataio.res.lba_high) << 16) |
441    ((u_int64_t)(ccb.ataio.res.lba_low_exp) << 24) |
442    ((u_int64_t)(ccb.ataio.res.lba_mid_exp) << 32) |
443    ((u_int64_t)(ccb.ataio.res.lba_high_exp) << 40);
444
445  request->u.ata.count = ccb.ataio.res.sector_count | (ccb.ataio.res.sector_count_exp << 8);
446  request->error = ccb.ataio.res.error;
447
448  return 0;
449}
450
451#endif
452
453/////////////////////////////////////////////////////////////////////////////
454/// Implement AMCC/3ware RAID support
455
456class freebsd_escalade_device
457: public /*implements*/ ata_device,
458  public /*extends*/ freebsd_smart_device
459{
460public:
461  freebsd_escalade_device(smart_interface * intf, const char * dev_name,
462    int escalade_type, int disknum);
463
464protected:
465  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
466  virtual bool open();
467
468private:
469  int m_escalade_type; ///< Type string for escalade_command_interface().
470  int m_disknum; ///< Disk number.
471};
472
473freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name,
474    int escalade_type, int disknum)
475: smart_device(intf, dev_name, "3ware", "3ware"),
476  freebsd_smart_device(
477    escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" :
478    escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" :
479    /*             CONTROLLER_3WARE_678K     */ "ATA"             ),
480  m_escalade_type(escalade_type), m_disknum(disknum)
481{
482  set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
483}
484
485bool freebsd_escalade_device::open()
486{
487  const char *dev = get_dev_name();
488  int fd;
489 
490  if ((fd = ::open(dev,O_RDWR))<0) {
491    set_err(errno);
492    return false;
493  }
494  set_fd(fd);
495  return true;
496}
497
498bool freebsd_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
499{
500  // to hold true file descriptor
501  int fd = get_fd();
502
503  if (!ata_cmd_is_ok(in,
504    true, // data_out_support
505    false, // TODO: multi_sector_support
506    true) // ata_48bit_support
507  )
508  return false;
509
510  struct twe_usercommand* cmd_twe = NULL;
511  TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
512  TWE_Command_ATA* ata = NULL;
513
514  // Used by both the SCSI and char interfaces
515  char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
516
517  if (m_disknum < 0) {
518    printwarning(NO_DISK_3WARE,NULL);
519    return -1;
520  }
521
522  memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
523
524  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
525    cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
526    cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
527    cmd_twa->driver_pkt.buffer_length = 512;
528    ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
529  } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
530    cmd_twe = (struct twe_usercommand*)ioctl_buffer;
531    ata = &cmd_twe->tu_command.ata;
532  } else {
533    return set_err(ENOSYS,
534      "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n"
535      "Please contact " PACKAGE_BUGREPORT "\n", (int)m_escalade_type, m_disknum);
536  }
537
538  ata->opcode = TWE_OP_ATA_PASSTHROUGH;
539
540  // Same for (almost) all commands - but some reset below
541  ata->request_id    = 0xFF;
542  ata->unit          = m_disknum;
543  ata->status        = 0;
544  ata->flags         = 0x1;
545  // Set registers
546  {
547    const ata_in_regs_48bit & r = in.in_regs;
548    ata->features     = r.features_16;
549    ata->sector_count = r.sector_count_16;
550    ata->sector_num   = r.lba_low_16;
551    ata->cylinder_lo  = r.lba_mid_16;
552    ata->cylinder_hi  = r.lba_high_16;
553    ata->drive_head   = r.device;
554    ata->command      = r.command;
555  }
556
557  // Is this a command that reads or returns 512 bytes?
558  // passthru->param values are:
559  // 0x0 - non data command without TFR write check,
560  // 0x8 - non data command with TFR write check,
561  // 0xD - data command that returns data to host from device
562  // 0xF - data command that writes data from host to device
563  // passthru->size values are 0x5 for non-data and 0x07 for data
564  bool readdata = false;
565  if (in.direction == ata_cmd_in::data_in) {
566    readdata=true;
567    ata->sgl_offset   = 0x5;
568    ata->size         = 0x5; // TODO: other values for multisector?
569    ata->param        = 0xD;
570    // For 64-bit to work correctly, up the size of the command packet
571    // in dwords by 1 to account for the 64-bit single sgl 'address'
572    // field. Note that this doesn't agree with the typedefs but it's
573    // right (agree with kernel driver behavior/typedefs).
574    // if (sizeof(long)==8)
575    //  ata->size++;
576  }
577  else if (in.direction == ata_cmd_in::no_data) {
578    // Non data command -- but doesn't use large sector
579    // count register values. 
580    ata->sgl_offset   = 0x0;
581    ata->size         = 0x5;
582    ata->param        = 0x8;
583    ata->sector_count = 0x0;
584  }
585
586  else if (in.direction == ata_cmd_in::data_out) {
587    // Non data command -- but doesn't use large sector
588    // count register values.
589    ata->sgl_offset   = 0x5;
590    ata->size         = 0x5; // TODO: not valid for multisector
591    ata->param        = 0xF; // PIO data write
592    if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
593      cmd_twe->tu_data = in.buffer;
594      cmd_twe->tu_size = in.size;
595    }
596    else if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
597       cmd_twa->pdata = in.buffer;
598       cmd_twa->driver_pkt.buffer_length = in.size;
599    }
600  }
601
602  // 3WARE controller can NOT have packet device internally
603  if (in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE) {
604    return set_err(ENODEV, "No drive on port %d", m_disknum);
605  }
606
607  // Now send the command down through an ioctl()
608  int ioctlreturn;
609  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
610    ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
611  } else {
612    ioctlreturn=ioctl(fd,TWEIO_COMMAND,cmd_twe);
613  }
614
615  // Deal with the different error cases
616  if (ioctlreturn) {
617    return set_err(EIO);
618  }
619
620  // See if the ATA command failed.  Now that we have returned from
621  // the ioctl() call, if passthru is valid, then:
622  // - ata->status contains the 3ware controller STATUS
623  // - ata->command contains the ATA STATUS register
624  // - ata->features contains the ATA ERROR register
625  //
626  // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
627  // If bit 0 (error bit) is set, then ATA ERROR register is valid.
628  // While we *might* decode the ATA ERROR register, at the moment it
629  // doesn't make much sense: we don't care in detail why the error
630  // happened.
631
632  if (ata->status || (ata->command & 0x21)) {
633    if (scsi_debugmode)
634      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);
635    return set_err(EIO);
636  }
637
638  // If this is a read data command, copy data to output buffer
639  if (readdata) {
640    if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR)
641      memcpy(in.buffer, cmd_twa->pdata, in.size);
642    else if(m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
643      memcpy(in.buffer, cmd_twe->tu_data, in.size); // untested
644    }
645  }
646  // Return register values
647  if (ata) {
648    ata_out_regs_48bit & r = out.out_regs;
649    r.error           = ata->features;
650    r.sector_count_16 = ata->sector_count;
651    r.lba_low_16      = ata->sector_num;
652    r.lba_mid_16      = ata->cylinder_lo;
653    r.lba_high_16     = ata->cylinder_hi;
654    r.device          = ata->drive_head;
655    r.status          = ata->command;
656  }
657  // look for nonexistent devices/ports
658  if (in.in_regs.command == ATA_IDENTIFY_DEVICE
659  && !nonempty((unsigned char *)in.buffer, in.size)) {
660    return set_err(ENODEV, "No drive on port %d", m_disknum);
661  }
662  return true;
663}
664
665
666/////////////////////////////////////////////////////////////////////////////
667/// Implement Highpoint RAID support with old functions
668
669class freebsd_highpoint_device
670: public /*implements*/ ata_device_with_command_set,
671  public /*extends*/ freebsd_smart_device
672{
673public:
674  freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
675    unsigned char controller, unsigned char channel, unsigned char port);
676
677protected:
678  virtual int ata_command_interface(smart_command_set command, int select, char * data);
679  virtual bool open();
680
681private:
682  unsigned char m_hpt_data[3]; ///< controller/channel/port
683};
684
685
686freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
687  unsigned char controller, unsigned char channel, unsigned char port)
688: smart_device(intf, dev_name, "hpt", "hpt"),
689  freebsd_smart_device("ATA")
690{
691  m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port;
692  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]);
693}
694
695bool freebsd_highpoint_device::open()
696{
697  const char *dev = get_dev_name();
698  int fd;
699 
700  if ((fd = ::open(dev,O_RDWR))<0) {
701    set_err(errno);
702    return false;
703  }
704  set_fd(fd);
705  return true;
706}
707
708int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
709{
710  int fd=get_fd(); 
711  int ids[2];
712  HPT_IOCTL_PARAM param;
713  HPT_CHANNEL_INFO_V2 info;
714  unsigned char* buff[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)];
715  PHPT_PASS_THROUGH_HEADER pide_pt_hdr, pide_pt_hdr_out;
716
717  // get internal deviceid
718  ids[0] = m_hpt_data[0] - 1;
719  ids[1] = m_hpt_data[1] - 1;
720
721  memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
722
723  param.magic = HPT_IOCTL_MAGIC;
724  param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO_V2;
725  param.in = (unsigned char *)ids;
726  param.in_size = sizeof(unsigned int) * 2;
727  param.out = (unsigned char *)&info;
728  param.out_size = sizeof(HPT_CHANNEL_INFO_V2);
729
730  if (m_hpt_data[2]==1) {
731    param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO;
732    param.out_size = sizeof(HPT_CHANNEL_INFO);
733  }
734  if (ioctl(fd, HPT_DO_IOCONTROL, &param)!=0 ||
735      info.devices[m_hpt_data[2]-1]==0) {
736    return -1;
737  }
738
739  // perform smart action
740  memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER));
741  pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff;
742
743  pide_pt_hdr->lbamid = 0x4f;
744  pide_pt_hdr->lbahigh = 0xc2;
745  pide_pt_hdr->command = ATA_SMART_CMD;
746  pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1];
747
748  switch (command){
749  case READ_VALUES:
750    pide_pt_hdr->feature=ATA_SMART_READ_VALUES;
751    pide_pt_hdr->protocol=HPT_READ;
752    break;
753  case READ_THRESHOLDS:
754    pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS;
755    pide_pt_hdr->protocol=HPT_READ;
756    break;
757  case READ_LOG:
758    pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR;
759    pide_pt_hdr->lbalow=select;
760    pide_pt_hdr->protocol=HPT_READ;
761    break;
762  case IDENTIFY:
763    pide_pt_hdr->command=ATA_IDENTIFY_DEVICE;
764    pide_pt_hdr->protocol=HPT_READ;
765    break;
766  case ENABLE:
767    pide_pt_hdr->feature=ATA_SMART_ENABLE;
768    break;
769  case DISABLE:
770    pide_pt_hdr->feature=ATA_SMART_DISABLE;
771    break;
772  case AUTO_OFFLINE:
773    pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE;
774    pide_pt_hdr->sectorcount=select;
775    break;
776  case AUTOSAVE:
777    pide_pt_hdr->feature=ATA_SMART_AUTOSAVE;
778    pide_pt_hdr->sectorcount=select;
779    break;
780  case IMMEDIATE_OFFLINE:
781    pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE;
782    pide_pt_hdr->lbalow=select;
783    break;
784  case STATUS_CHECK:
785  case STATUS:
786    pide_pt_hdr->feature=ATA_SMART_STATUS;
787    break;
788  case CHECK_POWER_MODE:
789    pide_pt_hdr->command=ATA_CHECK_POWER_MODE;
790    break;
791  case WRITE_LOG:
792    memcpy(buff+sizeof(HPT_PASS_THROUGH_HEADER), data, 512);
793    pide_pt_hdr->feature=ATA_SMART_WRITE_LOG_SECTOR;
794    pide_pt_hdr->lbalow=select;
795    pide_pt_hdr->protocol=HPT_WRITE;
796    break;
797  default:
798    pout("Unrecognized command %d in highpoint_command_interface()\n"
799         "Please contact " PACKAGE_BUGREPORT "\n", command);
800    errno=ENOSYS;
801    return -1;
802  }
803  if (pide_pt_hdr->protocol!=0) {
804    pide_pt_hdr->sectors = 1;
805    pide_pt_hdr->sectorcount = 1;
806  }
807
808  memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
809
810  param.magic = HPT_IOCTL_MAGIC;
811  param.ctrl_code = HPT_IOCTL_IDE_PASS_THROUGH;
812  param.in = (unsigned char *)buff;
813  param.in_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? 0 : pide_pt_hdr->sectors * 512);
814  param.out = (unsigned char *)buff+param.in_size;
815  param.out_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? pide_pt_hdr->sectors * 512 : 0);
816
817  pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out;
818
819  if ((ioctl(fd, HPT_DO_IOCONTROL, &param)!=0) ||
820      (pide_pt_hdr_out->command & 1)) {
821    return -1;
822  }
823
824  if (command==STATUS_CHECK)
825  {
826    unsigned const char normal_lo=0x4f, normal_hi=0xc2;
827    unsigned const char failed_lo=0xf4, failed_hi=0x2c;
828    unsigned char low,high;
829
830    high = pide_pt_hdr_out->lbahigh;
831    low = pide_pt_hdr_out->lbamid;
832
833    // Cyl low and Cyl high unchanged means "Good SMART status"
834    if (low==normal_lo && high==normal_hi)
835      return 0;
836
837    // These values mean "Bad SMART status"
838    if (low==failed_lo && high==failed_hi)
839      return 1;
840
841    // We haven't gotten output that makes sense; print out some debugging info
842    char buf[512];
843    sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
844            (int)pide_pt_hdr_out->command,
845            (int)pide_pt_hdr_out->feature,
846            (int)pide_pt_hdr_out->sectorcount,
847            (int)pide_pt_hdr_out->lbalow,
848            (int)pide_pt_hdr_out->lbamid,
849            (int)pide_pt_hdr_out->lbahigh,
850            (int)pide_pt_hdr_out->sectors);
851    printwarning(BAD_SMART,buf);
852  }
853  else if (command==CHECK_POWER_MODE)
854    data[0] = pide_pt_hdr_out->sectorcount & 0xff;
855  else if (pide_pt_hdr->protocol==HPT_READ)
856    memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER), 
857      pide_pt_hdr->sectors * 512);
858  return 0;
859}
860
861
862/////////////////////////////////////////////////////////////////////////////
863/// Standard SCSI support
864
865class freebsd_scsi_device
866: public /*implements*/ scsi_device,
867  public /*extends*/ freebsd_smart_device
868{
869public:
870  freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
871
872  virtual smart_device * autodetect_open();
873
874  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
875 
876  virtual bool open();
877
878  virtual bool close();
879 
880private:
881  int m_fd;
882  struct cam_device *m_camdev;
883};
884
885bool freebsd_scsi_device::open(){
886  const char *dev = get_dev_name();
887 
888  if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
889    set_err(errno);
890    return false;
891  }
892  set_fd(m_camdev->fd);
893  return true;
894}
895
896bool freebsd_scsi_device::close(){
897  cam_close_device(m_camdev);
898  set_fd(-1);
899  return true;
900}
901
902freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
903  const char * dev_name, const char * req_type)
904: smart_device(intf, dev_name, "scsi", req_type),
905  freebsd_smart_device("SCSI")
906{
907}
908
909
910bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
911{
912  int report=scsi_debugmode;
913  union ccb *ccb;
914
915  if (report > 0) {
916    unsigned int k;
917    const unsigned char * ucp = iop->cmnd;
918    const char * np;
919
920    np = scsi_get_opcode_name(ucp[0]);
921    pout(" [%s: ", np ? np : "<unknown opcode>");
922    for (k = 0; k < iop->cmnd_len; ++k)
923      pout("%02x ", ucp[k]);
924    if ((report > 1) && 
925      (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
926    int trunc = (iop->dxfer_len > 256) ? 1 : 0;
927
928    pout("]\n  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
929      (trunc ? " [only first 256 bytes shown]" : ""));
930    dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
931      }
932      else
933        pout("]");
934  }
935
936  if(m_camdev==NULL) {
937    warnx("error: camdev=0!");
938    return -ENOTTY;
939  }
940
941  if (!(ccb = cam_getccb(m_camdev))) {
942    warnx("error allocating ccb");
943    return -ENOMEM;
944  }
945  // mfi SAT layer is known to be buggy
946  if(!strcmp("mfi",m_camdev->sim_name)) {
947    if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { 
948      // Controller does not return ATA output registers in SAT sense data
949      if (iop->cmnd[2] & (1 << 5)) // chk_cond
950        return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware");
951    }
952    // SMART WRITE LOG SECTOR causing media errors
953    if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 && iop->cmnd[14] == ATA_SMART_CMD
954        && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || 
955        (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 && iop->cmnd[9] == ATA_SMART_CMD &&
956        iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) 
957      return set_err(ENOSYS, "SMART WRITE LOG SECTOR command is not supported by controller firmware"); 
958  }
959
960  // clear out structure, except for header that was filled in for us
961  bzero(&(&ccb->ccb_h)[1],
962    sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
963
964  cam_fill_csio(&ccb->csio,
965    /*retrires*/ 1,
966    /*cbfcnp*/ NULL,
967    /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)),
968    /* tagaction */ MSG_SIMPLE_Q_TAG,
969    /* dataptr */ iop->dxferp,
970    /* datalen */ iop->dxfer_len,
971    /* senselen */ iop->max_sense_len,
972    /* cdblen */ iop->cmnd_len,
973    /* timout (converted to seconds) */ iop->timeout*1000);
974  memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len);
975
976  if (cam_send_ccb(m_camdev,ccb) < 0) {
977    warn("error sending SCSI ccb");
978    cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
979    cam_freeccb(ccb);
980    return -EIO;
981  }
982
983  if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) {
984    cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
985    cam_freeccb(ccb);
986    return -EIO;
987  }
988
989  if (iop->sensep) {
990    iop->resp_sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
991    memcpy(iop->sensep,&(ccb->csio.sense_data),iop->resp_sense_len);
992  }
993
994  iop->scsi_status = ccb->csio.scsi_status;
995
996  cam_freeccb(ccb);
997
998  if (report > 0) {
999    int trunc;
1000
1001    pout("  status=0\n");
1002    trunc = (iop->dxfer_len > 256) ? 1 : 0;
1003
1004    pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
1005      (trunc ? " [only first 256 bytes shown]" : ""));
1006    dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
1007  }
1008
1009  return true;
1010}
1011
1012
1013/////////////////////////////////////////////////////////////////////////////
1014/// Areca RAID support
1015
1016///////////////////////////////////////////////////////////////////
1017// SATA(ATA) device behind Areca RAID Controller
1018class freebsd_areca_ata_device
1019: public /*implements*/ areca_ata_device,
1020  public /*extends*/ freebsd_smart_device
1021{
1022public:
1023  freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
1024  virtual smart_device * autodetect_open();
1025  virtual bool arcmsr_lock();
1026  virtual bool arcmsr_unlock();
1027  virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
1028};
1029
1030///////////////////////////////////////////////////////////////////
1031// SAS(SCSI) device behind Areca RAID Controller
1032class freebsd_areca_scsi_device
1033: public /*implements*/ areca_scsi_device,
1034  public /*extends*/ freebsd_smart_device
1035{
1036public:
1037  freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1);
1038  virtual smart_device * autodetect_open();
1039  virtual bool arcmsr_lock();
1040  virtual bool arcmsr_unlock();
1041  virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop);
1042};
1043
1044
1045// Areca RAID Controller(SATA Disk)
1046freebsd_areca_ata_device::freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
1047: smart_device(intf, dev_name, "areca", "areca"),
1048  freebsd_smart_device("ATA")
1049{
1050  set_disknum(disknum);
1051  set_encnum(encnum);
1052  set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
1053}
1054
1055
1056smart_device * freebsd_areca_ata_device::autodetect_open()
1057{
1058  int is_ata = 1;
1059
1060  // autodetect device type
1061  is_ata = arcmsr_get_dev_type();
1062  if(is_ata < 0)
1063  {
1064    set_err(EIO);
1065    return this;
1066  }
1067
1068  if(is_ata == 1)
1069  {
1070    // SATA device
1071    return this;
1072  }
1073
1074  // SAS device
1075  smart_device_auto_ptr newdev(new freebsd_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum()));
1076  close();
1077  delete this;
1078  newdev->open();       // TODO: Can possibly pass open fd
1079
1080  return newdev.release();
1081}
1082
1083int freebsd_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
1084{
1085  int ioctlreturn = 0;
1086
1087  if(!is_open()) {
1088      if(!open()){
1089      }
1090  }
1091
1092  ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp);
1093  if (ioctlreturn)
1094  {
1095    // errors found
1096    return -1;
1097  }
1098
1099  return ioctlreturn;
1100}
1101
1102bool freebsd_areca_ata_device::arcmsr_lock()
1103{
1104  return true;
1105}
1106
1107
1108bool freebsd_areca_ata_device::arcmsr_unlock()
1109{
1110  return true;
1111}
1112
1113
1114// Areca RAID Controller(SAS Device)
1115freebsd_areca_scsi_device::freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum)
1116: smart_device(intf, dev_name, "areca", "areca"),
1117  freebsd_smart_device("SCSI")
1118{
1119  set_disknum(disknum);
1120  set_encnum(encnum);
1121  set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum);
1122}
1123
1124smart_device * freebsd_areca_scsi_device::autodetect_open()
1125{
1126  return this;
1127}
1128
1129int freebsd_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop)
1130{
1131  int ioctlreturn = 0;
1132
1133  if(!is_open()) {
1134      if(!open()){
1135      }
1136  }
1137  ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp);
1138  if (ioctlreturn)
1139  {
1140    // errors found
1141    return -1;
1142  }
1143
1144  return ioctlreturn;
1145}
1146
1147bool freebsd_areca_scsi_device::arcmsr_lock()
1148{
1149  return true;
1150}
1151
1152
1153bool freebsd_areca_scsi_device::arcmsr_unlock()
1154{
1155  return true;
1156}
1157
1158
1159/////////////////////////////////////////////////////////////////////////////
1160/// Implement CCISS RAID support with old functions
1161
1162class freebsd_cciss_device
1163: public /*implements*/ scsi_device,
1164  public /*extends*/ freebsd_smart_device
1165{
1166public:
1167  freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
1168
1169  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
1170  virtual bool open();
1171
1172private:
1173  unsigned char m_disknum; ///< Disk number.
1174};
1175
1176bool freebsd_cciss_device::open()
1177{
1178  const char *dev = get_dev_name();
1179  int fd;
1180  if ((fd = ::open(dev,O_RDWR))<0) {
1181    set_err(errno);
1182    return false;
1183  }
1184  set_fd(fd);
1185  return true;
1186}
1187
1188freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
1189  const char * dev_name, unsigned char disknum)
1190: smart_device(intf, dev_name, "cciss", "cciss"),
1191  freebsd_smart_device("SCSI"),
1192  m_disknum(disknum)
1193{
1194  set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
1195}
1196
1197bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
1198{
1199  int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode);
1200  if (status < 0)
1201      return set_err(-status);
1202  return true;
1203  // not reached
1204  return true;
1205}
1206
1207
1208/////////////////////////////////////////////////////////////////////////////
1209/// SCSI open with autodetection support
1210
1211smart_device * freebsd_scsi_device::autodetect_open()
1212{
1213  // Open device
1214  if (!open())
1215    return this;
1216
1217  // No Autodetection if device type was specified by user
1218  if (*get_req_type())
1219    return this;
1220
1221  // The code below is based on smartd.cpp:SCSIFilterKnown()
1222
1223  // Get INQUIRY
1224  unsigned char req_buff[64] = {0, };
1225  int req_len = 36;
1226  if (scsiStdInquiry(this, req_buff, req_len)) {
1227    // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
1228    // watch this spot ... other devices could lock up here
1229    req_len = 64;
1230    if (scsiStdInquiry(this, req_buff, req_len)) {
1231      // device doesn't like INQUIRY commands
1232      close();
1233      set_err(EIO, "INQUIRY failed");
1234      return this;
1235    }
1236  }
1237
1238  int avail_len = req_buff[4] + 5;
1239  int len = (avail_len < req_len ? avail_len : req_len);
1240  if (len < 36)
1241    return this;
1242
1243  // Use INQUIRY to detect type
1244
1245  // 3ware ?
1246  if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
1247    close();
1248    set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
1249                    "you may need to replace %s with /dev/twaN, /dev/tweN or /dev/twsN", get_dev_name());
1250    return this;
1251  }
1252
1253  // SAT or USB, skip MFI controllers because of bugs
1254  {
1255    smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
1256    if (newdev) {
1257      // NOTE: 'this' is now owned by '*newdev'
1258      if(!strcmp("mfi",m_camdev->sim_name)) {
1259        newdev->close();
1260        newdev->set_err(ENOSYS, "SATA device detected,\n"
1261          "MegaRAID SAT layer is reportedly buggy, use '-d sat' to try anyhow");
1262      }
1263      return newdev;
1264    }
1265  }
1266
1267  // Nothing special found
1268  return this;
1269}
1270
1271
1272/////////////////////////////////////////////////////////////////////////////
1273/// Implement platform interface with old functions.
1274
1275class freebsd_smart_interface
1276: public /*implements*/ smart_interface
1277{
1278public:
1279  virtual std::string get_os_version_str();
1280
1281  virtual std::string get_app_examples(const char * appname);
1282
1283  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
1284    const char * pattern = 0);
1285
1286protected:
1287  virtual ata_device * get_ata_device(const char * name, const char * type);
1288
1289#if FREEBSDVER > 800100
1290  virtual ata_device * get_atacam_device(const char * name, const char * type);
1291#endif
1292
1293  virtual scsi_device * get_scsi_device(const char * name, const char * type);
1294
1295  virtual smart_device * autodetect_smart_device(const char * name);
1296
1297  virtual smart_device * get_custom_smart_device(const char * name, const char * type);
1298
1299  virtual std::string get_valid_custom_dev_types_str();
1300};
1301
1302
1303//////////////////////////////////////////////////////////////////////
1304
1305std::string freebsd_smart_interface::get_os_version_str()
1306{
1307  struct utsname osname;
1308  uname(&osname);
1309  return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
1310}
1311
1312std::string freebsd_smart_interface::get_app_examples(const char * appname)
1313{
1314  if (!strcmp(appname, "smartctl"))
1315    return smartctl_examples;
1316  return "";
1317}
1318
1319ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
1320{
1321  return new freebsd_ata_device(this, name, type);
1322}
1323
1324#if FREEBSDVER > 800100
1325ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type)
1326{
1327  return new freebsd_atacam_device(this, name, type);
1328}
1329#endif
1330
1331scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
1332{
1333  return new freebsd_scsi_device(this, name, type);
1334}
1335
1336// we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
1337// devices on system despite of it's names
1338//
1339// If any errors occur, leave errno set as it was returned by the
1340// system call, and return <0.
1341//
1342// arguments:
1343// names: resulting array
1344// show_all - export duplicate device name or not
1345//
1346// Return values:
1347// -1:   error
1348// >=0: number of discovered devices
1349
1350bool get_dev_names_cam(std::vector<std::string> & names, bool show_all)
1351{
1352  int fd;
1353  if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
1354    if (errno == ENOENT) /* There are no CAM device on this computer */
1355      return 0;
1356    int serrno = errno;
1357    pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
1358    errno = serrno;
1359    return false;
1360  }
1361
1362  union ccb ccb;
1363  bzero(&ccb, sizeof(union ccb));
1364
1365  ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
1366  ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1367  ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1368
1369  ccb.ccb_h.func_code = XPT_DEV_MATCH;
1370  int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
1371  ccb.cdm.match_buf_len = bufsize;
1372  // TODO: Use local buffer instead of malloc() if possible
1373  ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
1374  bzero(ccb.cdm.matches,bufsize); // clear ccb.cdm.matches structure
1375 
1376  if (ccb.cdm.matches == NULL) {
1377    close(fd);
1378    throw std::bad_alloc();
1379  }
1380  ccb.cdm.num_matches = 0;
1381  ccb.cdm.num_patterns = 0;
1382  ccb.cdm.pattern_buf_len = 0;
1383
1384  /*
1385   * We do the ioctl multiple times if necessary, in case there are
1386   * more than MAX_NUM_DEV nodes in the EDT.
1387   */
1388  int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool
1389  std::string devname;
1390  do {
1391    if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1392      int serrno = errno;
1393      pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
1394      free(ccb.cdm.matches);
1395      close(fd);
1396      errno = serrno;
1397      return false;
1398    }
1399
1400    if ((ccb.ccb_h.status != CAM_REQ_CMP)
1401      || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
1402      && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
1403      pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
1404      free(ccb.cdm.matches);
1405      close(fd);
1406      errno = ENXIO;
1407      return false;
1408    }
1409
1410    for (unsigned i = 0; i < ccb.cdm.num_matches; i++) {
1411      struct bus_match_result *bus_result;
1412      struct device_match_result *dev_result;
1413      struct periph_match_result *periph_result;
1414
1415      if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
1416        bus_result = &ccb.cdm.matches[i].result.bus_result;
1417
1418        if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
1419        skip_bus = 1;
1420        else
1421          skip_bus = 0;
1422        changed = 1;
1423      } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
1424        dev_result = &ccb.cdm.matches[i].result.device_result;
1425
1426        if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
1427          skip_device = 1;
1428        else
1429          skip_device = 0;
1430       
1431        //        /* Shall we skip non T_DIRECT devices ? */
1432        //        if (dev_result->inq_data.device != T_DIRECT)
1433        //          skip_device = 1;
1434        changed = 1;
1435      } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && 
1436          (skip_device == 0 || show_all)) { 
1437        /* One device may be populated as many peripherals (pass0 & da0 for example).
1438        * We are searching for latest name
1439        */
1440        periph_result =  &ccb.cdm.matches[i].result.periph_result;
1441        devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
1442        changed = 0;
1443      };
1444      if ((changed == 1 || show_all) && !devname.empty()) {
1445        names.push_back(devname);
1446        devname.erase();
1447        changed = 0;
1448      };
1449    }
1450
1451  } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
1452
1453  if (!devname.empty())
1454    names.push_back(devname);
1455
1456  free(ccb.cdm.matches);
1457  close(fd);
1458  return true;
1459}
1460
1461// we are using ATA subsystem enumerator to found all ATA devices on system
1462// despite of it's names
1463//
1464// If any errors occur, leave errno set as it was returned by the
1465// system call, and return <0.
1466
1467// Return values:
1468// -1:   error
1469// >=0: number of discovered devices
1470int get_dev_names_ata(char*** names) {
1471  struct ata_ioc_devices devices;
1472  int fd=-1,maxchannel,serrno=-1,n=0;
1473  char **mp = NULL;
1474
1475  *names=NULL;
1476
1477  if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
1478    if (errno == ENOENT) /* There are no ATA device on this computer */
1479      return 0;
1480    serrno = errno;
1481    pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
1482    n = -1;
1483    goto end;
1484  };
1485
1486  if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
1487    serrno = errno;
1488    pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
1489    n = -1;
1490    goto end;
1491  };
1492
1493  // allocate space for up to MAX_NUM_DEV number of ATA devices
1494  mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
1495  if (mp == NULL) {
1496    serrno=errno;
1497    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
1498    n = -1;
1499    goto end;
1500  };
1501
1502  for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
1503    int j;
1504
1505    if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
1506      if (errno == ENXIO)
1507        continue; /* such channel not exist */
1508      pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
1509      n = -1;
1510      goto end;
1511    };
1512    for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
1513      if (devices.name[j][0] != '\0') {
1514        asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
1515        if (mp[n] == NULL) {
1516          pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
1517          n = -1;
1518          goto end;
1519        };
1520        bytes+=1+strlen(mp[n]);
1521        n++;
1522      };
1523    };
1524  }; 
1525  mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
1526  if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL
1527    serrno=errno;
1528    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
1529    n = -1;
1530    goto end;
1531  };
1532  bytes += (n)*(sizeof(char*)); // and set allocated byte count
1533
1534end:
1535  if (fd>=0)
1536    close(fd);
1537  if (n <= 0) {
1538    free(mp);
1539    mp = NULL;
1540  }
1541
1542  *names=mp;
1543
1544  if (serrno>-1)
1545    errno=serrno;
1546  return n;
1547}
1548
1549
1550
1551bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
1552  const char * type, const char * pattern /*= 0*/)
1553{
1554  if (pattern) {
1555    set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
1556    return false;
1557  }
1558
1559  // Make namelists
1560  char * * atanames = 0; int numata = 0;
1561  if (!type || !strcmp(type, "ata")) {
1562    numata = get_dev_names_ata(&atanames);
1563    if (numata < 0) {
1564      set_err(ENOMEM);
1565      return false;
1566    }
1567  }
1568
1569  std::vector<std::string> scsinames;
1570  if (!type || !strcmp(type, "scsi")) { // do not export duplicated names
1571    if (!get_dev_names_cam(scsinames, false)) {
1572      set_err(errno);
1573      return false;
1574    }
1575  }
1576
1577  // Add to devlist
1578  int i;
1579  if (type==NULL)
1580    type="";
1581  for (i = 0; i < numata; i++) {
1582    ata_device * atadev = get_ata_device(atanames[i], type);
1583    if (atadev)
1584      devlist.push_back(atadev);
1585    free(atanames[i]);
1586  }
1587  if(numata) free(atanames);
1588
1589  for (i = 0; i < (int)scsinames.size(); i++) {
1590    if(!*type) { // try USB autodetection if no type specified
1591      smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str());
1592      if(smartdev)
1593        devlist.push_back(smartdev);
1594    }
1595    else {
1596      scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type);
1597      if (scsidev)
1598        devlist.push_back(scsidev);
1599    }
1600  }
1601  return true;
1602}
1603
1604
1605#if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
1606static char done[USB_MAX_DEVICES];
1607
1608static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
1609  unsigned short & product_id, unsigned short & version)
1610{ 
1611
1612  struct usb_device_info di;
1613  int e, p, i;
1614  char devname[256];
1615
1616  snprintf(devname, sizeof(devname),"umass%d",busno);
1617
1618  di.udi_addr = a;
1619  e = ioctl(f, USB_DEVICEINFO, &di);
1620  if (e) {
1621    if (errno != ENXIO)
1622      printf("addr %d: I/O error\n", a);
1623    return 0;
1624  }
1625  done[a] = 1;
1626
1627  // list devices
1628  for (i = 0; i < USB_MAX_DEVNAMES; i++) {
1629    if (di.udi_devnames[i][0]) {
1630      if(strcmp(di.udi_devnames[i],devname)==0) {
1631        // device found!
1632        vendor_id = di.udi_vendorNo;
1633        product_id = di.udi_productNo;
1634        version = di.udi_releaseNo;
1635        return 1;
1636        // FIXME
1637      }
1638    }
1639  }
1640  if (!rec)
1641    return 0;
1642  for (p = 0; p < di.udi_nports; p++) {
1643    int s = di.udi_ports[p];
1644    if (s >= USB_MAX_DEVICES) {
1645      continue;
1646    }
1647    if (s == 0)
1648      printf("addr 0 should never happen!\n");
1649    else {
1650      if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
1651    }
1652  }
1653  return 0;
1654}
1655#endif
1656
1657
1658static int usbdevlist(int busno,unsigned short & vendor_id,
1659  unsigned short & product_id, unsigned short & version)
1660{
1661#if (FREEBSDVER >= 800000) // libusb2 interface
1662  struct libusb20_device *pdev = NULL;
1663  struct libusb20_backend *pbe;
1664  uint32_t matches = 0;
1665  char buf[128]; // do not change!
1666  char devname[128];
1667  uint8_t n;
1668  struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
1669
1670  pbe = libusb20_be_alloc_default();
1671
1672  while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
1673    matches++;
1674
1675    if (libusb20_dev_open(pdev, 0)) {
1676      warnx("libusb20_dev_open: could not open device");
1677      return 0;
1678    }
1679
1680    pdesc=libusb20_dev_get_device_desc(pdev);
1681
1682    snprintf(devname, sizeof(devname),"umass%d:",busno);
1683    for (n = 0; n != 255; n++) {
1684      if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
1685        break;
1686      if (buf[0] == 0)
1687        continue;
1688      if(strncmp(buf,devname,strlen(devname))==0){
1689        // found!
1690        vendor_id = pdesc->idVendor;
1691        product_id = pdesc->idProduct;
1692        version = pdesc->bcdDevice;
1693        libusb20_dev_close(pdev);
1694        libusb20_be_free(pbe);
1695        return 1;
1696      }
1697    }
1698
1699    libusb20_dev_close(pdev);
1700  }
1701
1702  if (matches == 0) {
1703    printf("No device match or lack of permissions.\n");
1704  }
1705
1706  libusb20_be_free(pbe);
1707
1708  return false;
1709#else // freebsd < 8.0 USB stack, ioctl interface
1710
1711  int  i, f, a, rc;
1712  char buf[50];
1713  int ncont;
1714
1715  for (ncont = 0, i = 0; i < 10; i++) {
1716    snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
1717    f = open(buf, O_RDONLY);
1718    if (f >= 0) {
1719      memset(done, 0, sizeof done);
1720      for (a = 1; a < USB_MAX_DEVICES; a++) {
1721        if (!done[a]) {
1722          rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
1723          if(rc) return 1;
1724        }
1725
1726      }
1727      close(f);
1728    } else {
1729      if (errno == ENOENT || errno == ENXIO)
1730        continue;
1731      warn("%s", buf);
1732    }
1733    ncont++;
1734  }
1735  return 0;
1736#endif
1737}
1738
1739smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
1740{
1741  unsigned short vendor_id = 0, product_id = 0, version = 0;
1742  struct cam_device *cam_dev;
1743  union ccb ccb;
1744  int bus=-1;
1745  int i,c;
1746  int len;
1747  const char * test_name = name;
1748
1749  // if dev_name null, or string length zero
1750  if (!name || !(len = strlen(name)))
1751    return 0;
1752
1753  // Dereference symlinks
1754  struct stat st;
1755  std::string pathbuf;
1756  if (!lstat(name, &st) && S_ISLNK(st.st_mode)) {
1757    char * p = realpath(name, (char *)0);
1758    if (p) {
1759      pathbuf = p;
1760      free(p);
1761      test_name = pathbuf.c_str();
1762    }
1763  }
1764
1765  // check ATA bus
1766  char * * atanames = 0; int numata = 0;
1767  numata = get_dev_names_ata(&atanames);
1768  if (numata > 0) {
1769    // check ATA/ATAPI devices
1770    for (i = 0; i < numata; i++) {
1771      if(!strcmp(atanames[i],test_name)) {
1772        for (c = i; c < numata; c++) free(atanames[c]);
1773        free(atanames);
1774        return new freebsd_ata_device(this, test_name, "");
1775      }
1776      else free(atanames[i]);
1777    }
1778    if(numata) free(atanames);
1779  }
1780  else {
1781    if (numata < 0)
1782      pout("Unable to get ATA device list\n");
1783  }
1784
1785  // check CAM
1786  std::vector<std::string> scsinames;
1787  if (!get_dev_names_cam(scsinames, true))
1788    pout("Unable to get CAM device list\n");
1789  else if (!scsinames.empty()) {
1790    // check all devices on CAM bus
1791    for (i = 0; i < (int)scsinames.size(); i++) {
1792      if(strcmp(scsinames[i].c_str(), test_name)==0)
1793      { // our disk device is CAM
1794        if ((cam_dev = cam_open_device(test_name, O_RDWR)) == NULL) {
1795          // open failure
1796          set_err(errno);
1797          return 0;
1798        }
1799        // zero the payload
1800        bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE);
1801        ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device
1802        if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
1803          warn("Get Transfer Settings CCB failed\n"
1804            "%s", strerror(errno));
1805          cam_close_device(cam_dev);
1806          return 0;
1807        }
1808        // now check if we are working with USB device, see umass.c
1809        if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found
1810          usbdevlist(bus,vendor_id, product_id, version);
1811          int bus=ccb.cpi.unit_number; // unit_number will match umass number
1812          cam_close_device(cam_dev);
1813          if(usbdevlist(bus,vendor_id, product_id, version)){
1814            const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
1815            if (usbtype)
1816              return get_sat_device(usbtype, new freebsd_scsi_device(this, test_name, ""));
1817          }
1818          return 0;
1819        }
1820#if FREEBSDVER > 800100
1821        // check if we have ATA device connected to CAM (ada)
1822        if(ccb.cpi.protocol == PROTO_ATA){
1823          cam_close_device(cam_dev);
1824          return new freebsd_atacam_device(this, test_name, "");
1825        }
1826#endif
1827        // close cam device, we don`t need it anymore
1828        cam_close_device(cam_dev);
1829        // handle as usual scsi
1830        return new freebsd_scsi_device(this, test_name, "");     
1831      }
1832    }
1833  }
1834  // device is LSI raid supported by mfi driver
1835  if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid")))
1836    set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information");
1837  // device type unknown
1838  return 0;
1839}
1840
1841
1842smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
1843{
1844  // 3Ware ?
1845  static const char * fbsd_dev_twe_ctrl = "/dev/twe";
1846  static const char * fbsd_dev_twa_ctrl = "/dev/twa";
1847  static const char * fbsd_dev_tws_ctrl = "/dev/tws";
1848  int disknum = -1, n1 = -1, n2 = -1, contr = -1;
1849
1850  if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
1851    if (n2 != (int)strlen(type)) {
1852      set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
1853      return 0;
1854    }
1855    if (!(0 <= disknum && disknum <= 127)) {
1856      set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
1857      return 0;
1858    }
1859
1860    // guess 3ware device type based on device name
1861    if (str_starts_with(name, fbsd_dev_twa_ctrl) ||
1862        str_starts_with(name, fbsd_dev_tws_ctrl)   ) {
1863      contr=CONTROLLER_3WARE_9000_CHAR;
1864    }
1865    if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){
1866      contr=CONTROLLER_3WARE_678K_CHAR;
1867    }
1868
1869    if(contr == -1){
1870      set_err(EINVAL, "3ware controller type unknown, use %sX, %sX or %sX devices", 
1871        fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl, fbsd_dev_tws_ctrl);
1872      return 0;
1873    }
1874    return new freebsd_escalade_device(this, name, contr, disknum);
1875  }
1876
1877  // Highpoint ?
1878  int controller = -1, channel = -1; disknum = 1;
1879  n1 = n2 = -1; int n3 = -1;
1880  if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
1881    int len = strlen(type);
1882    if (!(n2 == len || n3 == len)) {
1883      set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
1884      return 0;
1885    }
1886    if (!(1 <= controller && controller <= 8)) {
1887      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
1888      return 0;
1889    }
1890    if (!(1 <= channel && channel <= 16)) {
1891      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
1892      return 0;
1893    }
1894    if (!(1 <= disknum && disknum <= 15)) {
1895      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
1896      return 0;
1897    }
1898    return new freebsd_highpoint_device(this, name, controller, channel, disknum);
1899  }
1900
1901  // CCISS ?
1902  disknum = n1 = n2 = -1;
1903  if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
1904    if (n2 != (int)strlen(type)) {
1905      set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
1906      return 0;
1907    }
1908    if (!(0 <= disknum && disknum <= 127)) {
1909      set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
1910      return 0;
1911    }
1912    return get_sat_device("sat,auto", new freebsd_cciss_device(this, name, disknum));
1913  }
1914#if FREEBSDVER > 800100
1915  // adaX devices ?
1916  if(!strcmp(type,"atacam"))
1917    return new freebsd_atacam_device(this, name, "");
1918#endif
1919  // Areca?
1920  disknum = n1 = n2 = -1;
1921  int encnum = 1;
1922  if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
1923    if (!(1 <= disknum && disknum <= 128)) {
1924      set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
1925      return 0;
1926    }
1927    if (!(1 <= encnum && encnum <= 8)) {
1928      set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
1929      return 0;
1930    }
1931    return new freebsd_areca_ata_device(this, name, disknum, encnum);
1932  }
1933
1934  return 0;
1935}
1936
1937std::string freebsd_smart_interface::get_valid_custom_dev_types_str()
1938{
1939  return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E"
1940#if FREEBSDVER > 800100
1941  ", atacam"
1942#endif
1943  ;
1944}
1945
1946} // namespace
1947
1948/////////////////////////////////////////////////////////////////////////////
1949/// Initialize platform interface and register with smi()
1950
1951void smart_interface::init()
1952{
1953  static os_freebsd::freebsd_smart_interface the_interface;
1954  smart_interface::set(&the_interface);
1955}
Note: See TracBrowser for help on using the browser.