root/trunk/smartmontools/os_freebsd.cpp @ 2932

Revision 2932, 64.7 KB (checked in by samm2, 5 years ago)

FreeBSD: cam_get_umassno rewritten

  • 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-8 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 <camlib.h>
24#include <cam/scsi/scsi_message.h>
25#include <cam/scsi/scsi_pass.h>
26#if defined(__DragonFly__)
27#include <sys/nata.h>
28#else
29#include <sys/ata.h>
30#endif
31#include <sys/stat.h>
32#include <unistd.h>
33#include <glob.h>
34#include <stddef.h>
35#include <paths.h>
36#include <sys/utsname.h>
37
38#include "config.h"
39#include "int64.h"
40#include "atacmds.h"
41#include "scsicmds.h"
42#include "cciss.h"
43#include "utility.h"
44#include "extern.h"
45#include "os_freebsd.h"
46
47#include "dev_interface.h"
48#include "dev_ata_cmd_set.h"
49
50#define USBDEV "/dev/usb"
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
66
67#define CONTROLLER_UNKNOWN              0x00
68#define CONTROLLER_ATA                  0x01  // ATA/IDE/SATA
69#define CONTROLLER_SCSI                 0x02  // SCSI
70#define CONTROLLER_3WARE_678K           0x03  // NOT set by guess_device_type()
71#define CONTROLLER_3WARE_9000_CHAR      0x04  // set by guess_device_type()
72#define CONTROLLER_3WARE_678K_CHAR      0x05  // set by guess_device_type()
73#define CONTROLLER_HPT                  0x06  // SATA drives behind HighPoint Raid controllers
74#define CONTROLLER_CCISS                0x07  // CCISS controller
75#define CONTROLLER_ATACAM               0x08  // AHCI SATA controller
76
77static __unused const char *filenameandversion="$Id$";
78
79const char *os_XXXX_c_cvsid="$Id$" \
80ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
81
82extern smartmonctrl * con;
83
84// Private table of open devices: guaranteed zero on startup since
85// part of static data.
86struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV];
87
88// Returns 1 if device not available/open/found else 0.  Also shifts fd into valid range.
89static int isnotopen(int *fd, struct freebsd_dev_channel** fdchan) {
90  // put valid "file descriptor" into range 0...FREEBSD_MAXDEV-1
91  *fd -= FREEBSD_FDOFFSET;
92
93  // check for validity of "file descriptor".
94  if (*fd<0 || *fd>=FREEBSD_MAXDEV || !((*fdchan)=devicetable[*fd])) {
95    errno = ENODEV;
96    return 1;
97  }
98
99  return 0;
100}
101
102#define NO_RETURN 0
103#define BAD_SMART 1
104#define NO_DISK_3WARE 2
105#define BAD_KERNEL 3
106#define MAX_MSG 3
107
108// Utility function for printing warnings
109void printwarning(int msgNo, const char* extra) {
110  static int printed[] = {0,0,0,0};
111  static const char* message[]={
112    "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",
113
114    "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n",
115
116    "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
117
118    "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
119  };
120
121  if (msgNo >= 0 && msgNo <= MAX_MSG) {
122    if (!printed[msgNo]) {
123      printed[msgNo] = 1;
124      pout("%s", message[msgNo]);
125      if (extra)
126        pout("%s",extra);
127    }
128  }
129  return;
130}
131
132// Interface to ATA devices behind 3ware escalade RAID controller cards.  See os_linux.c
133
134#define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520
135#define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048
136#define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
137
138#ifndef ATA_DEVICE
139#define ATA_DEVICE "/dev/ata"
140#endif
141
142// global variable holding byte count of allocated memory
143long long bytes;
144
145const char * dev_freebsd_cpp_cvsid = "$Id$"
146  DEV_INTERFACE_H_CVSID;
147
148extern smartmonctrl * con; // con->reportscsiioctl
149
150/////////////////////////////////////////////////////////////////////////////
151
152#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
153int ata_identify_is_cached(int fd);
154#endif
155
156/////////////////////////////////////////////////////////////////////////////
157
158namespace os_freebsd { // No need to publish anything, name provided for Doxygen
159
160/////////////////////////////////////////////////////////////////////////////
161/// Implement shared open/close routines with old functions.
162
163class freebsd_smart_device
164: virtual public /*implements*/ smart_device
165{
166public:
167  explicit freebsd_smart_device(const char * mode)
168    : smart_device(never_called),
169      m_fd(-1), m_mode(mode) { }
170
171  virtual ~freebsd_smart_device() throw();
172
173  virtual bool is_open() const;
174
175  virtual bool open();
176
177  virtual bool close();
178
179protected:
180  /// Return filedesc for derived classes.
181  int get_fd() const
182    { return m_fd; }
183
184private:
185  int m_fd; ///< filedesc, -1 if not open.
186  const char * m_mode; ///< Mode string for deviceopen().
187};
188
189#ifdef __GLIBC__
190static inline void * reallocf(void *ptr, size_t size) {
191   void *rv = realloc(ptr, size);
192   if(rv == NULL)
193     free(ptr);
194   return rv;
195   }
196#endif
197
198freebsd_smart_device::~freebsd_smart_device() throw()
199{
200  if (m_fd >= 0)
201    os_freebsd::freebsd_smart_device::close();
202}
203
204// migration from the old_style
205unsigned char m_controller_type;
206unsigned char m_controller_port; 
207
208// examples for smartctl
209static const char  smartctl_examples[] =
210   "=================================================== SMARTCTL EXAMPLES =====\n\n"
211         "  smartctl -a /dev/ad0                       (Prints all SMART information)\n\n"
212         "  smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
213         "                                              (Enables SMART on first disk)\n\n"
214         "  smartctl -t long /dev/ad0              (Executes extended disk self-test)\n\n"
215         "  smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
216         "                                      (Prints Self-Test & Attribute errors)\n"
217         "                                      (Prints Self-Test & Attribute errors)\n\n"
218         "  smartctl -a --device=3ware,2 /dev/twa0\n"
219         "  smartctl -a --device=3ware,2 /dev/twe0\n"
220         "                              (Prints all SMART information for ATA disk on\n"
221         "                                 third port of first 3ware RAID controller)\n"
222  "  smartctl -a --device=cciss,0 /dev/ciss0\n"
223         "                              (Prints all SMART information for first disk \n"
224         "                               on Common Interface for SCSI-3 Support driver)\n"
225
226         ;
227
228bool freebsd_smart_device::is_open() const
229{
230  return (m_fd >= 0);
231}
232
233
234static int hpt_hba(const char* name) {
235  int i=0;
236  const char *hpt_node[]={"hptmv", "hptmv6", "hptrr", "hptiop", "hptmviop", "hpt32xx", "rr2320",
237  "rr232x", "rr2310", "rr2310_00", "rr2300", "rr2340", "rr1740", NULL};
238  while (hpt_node[i]) {
239    if (!strncmp(name, hpt_node[i], strlen(hpt_node[i])))
240      return 1;
241    i++;
242  }
243  return 0;
244}
245
246static int get_tw_channel_unit (const char* name, int* unit, int* dev) {
247  const char *p;
248  /* device node sanity check */
249  for (p = name + 3; *p; p++)
250    if (*p < '0' || *p > '9')
251    return -1;
252  if (strlen(name) > 4 && *(name + 3) == '0')
253    return -1;
254
255  if (dev != NULL)
256    *dev=atoi(name + 3);
257
258  /* no need for unit number */
259  if (unit != NULL)
260    *unit=0;
261  return 0;
262}
263
264#ifndef IOCATAREQUEST
265static int get_ata_channel_unit ( const char* name, int* unit, int* dev) {
266#ifndef ATAREQUEST
267  *dev=0;
268  *unit=0;
269  return 0;
270#else
271  // there is no direct correlation between name 'ad0, ad1, ...' and
272  // channel/unit number.  So we need to iterate through the possible
273  // channels and check each unit to see if we match names
274  struct ata_cmd iocmd;
275  int fd,maxunit;
276
277  bzero(&iocmd, sizeof(struct ata_cmd));
278
279  if ((fd = open(ATA_DEVICE, O_RDWR)) < 0)
280    return -errno;
281
282  iocmd.cmd = ATAGMAXCHANNEL;
283  if (ioctl(fd, IOCATA, &iocmd) < 0) {
284    return -errno;
285    close(fd);
286  }
287  maxunit = iocmd.u.maxchan;
288  for (*unit = 0; *unit < maxunit; (*unit)++) {
289    iocmd.channel = *unit;
290    iocmd.device = -1;
291    iocmd.cmd = ATAGPARM;
292    if (ioctl(fd, IOCATA, &iocmd) < 0) {
293      close(fd);
294      return -errno;
295    }
296    if (iocmd.u.param.type[0] && !strcmp(name,iocmd.u.param.name[0])) {
297      *dev = 0;
298      break;
299    }
300    if (iocmd.u.param.type[1] && !strcmp(name,iocmd.u.param.name[1])) {
301      *dev = 1;
302      break;
303    }
304  }
305  close(fd);
306  if (*unit == maxunit)
307    return -1;
308  else
309    return 0;
310#endif
311}
312#endif
313
314// Guess device type (ata or scsi) based on device name (FreeBSD
315// specific) SCSI device name in FreeBSD can be sd, sr, scd, st, nst,
316// osst, nosst and sg.
317static const char * fbsd_dev_prefix = _PATH_DEV;
318static const char * fbsd_dev_ata_disk_prefix = "ad";
319static const char * fbsd_dev_atacam_disk_prefix = "ada";
320static const char * fbsd_dev_scsi_disk_plus = "da";
321static const char * fbsd_dev_scsi_pass = "pass";
322static const char * fbsd_dev_scsi_tape1 = "sa";
323static const char * fbsd_dev_scsi_tape2 = "nsa";
324static const char * fbsd_dev_scsi_tape3 = "esa";
325static const char * fbsd_dev_twe_ctrl = "twe";
326static const char * fbsd_dev_twa_ctrl = "twa";
327static const char * fbsd_dev_cciss = "ciss";
328
329int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan, const char * type) {
330  int len;
331  int dev_prefix_len = strlen(fbsd_dev_prefix);
332
333
334  // No Autodetection if device type was specified by user
335  if (*type){
336    if(!strcmp(type,"ata")) return CONTROLLER_ATA;
337    if(!strcmp(type,"atacam")) return CONTROLLER_ATACAM;
338    if(!strcmp(type,"cciss")) return CONTROLLER_CCISS;
339    if(!strcmp(type,"scsi") || !strcmp(type,"sat")) goto handlescsi;
340    if(!strcmp(type,"3ware")){
341      return  parse_ata_chan_dev(dev_name,NULL,"");
342    }
343    if(!strcmp(type,"hpt")) return CONTROLLER_HPT;
344    return CONTROLLER_UNKNOWN;
345    // todo - add other types
346  }
347
348  // if dev_name null, or string length zero
349  if (!dev_name || !(len = strlen(dev_name)))
350    return CONTROLLER_UNKNOWN;
351
352  // Remove the leading /dev/... if it's there
353  if (!strncmp(fbsd_dev_prefix, dev_name, dev_prefix_len)) {
354    if (len <= dev_prefix_len) 
355      // if nothing else in the string, unrecognized
356    return CONTROLLER_UNKNOWN;
357    // else advance pointer to following characters
358    dev_name += dev_prefix_len;
359  }
360
361  // form /dev/ada* or ada*
362  if (!strncmp(fbsd_dev_atacam_disk_prefix, dev_name,
363               strlen(fbsd_dev_atacam_disk_prefix))) {
364    return CONTROLLER_ATACAM;
365  }
366
367  // form /dev/ad* or ad*
368  if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name,
369    strlen(fbsd_dev_ata_disk_prefix))) {
370#ifndef IOCATAREQUEST
371  if (chan != NULL) {
372    if (get_ata_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
373      return CONTROLLER_UNKNOWN;
374    }
375  }
376#endif
377    return CONTROLLER_ATA;
378  }
379
380  // form /dev/pass* or pass*
381  if (!strncmp(fbsd_dev_scsi_pass, dev_name,
382    strlen(fbsd_dev_scsi_pass)))
383    goto handlescsi;
384
385  // form /dev/da* or da*
386  if (!strncmp(fbsd_dev_scsi_disk_plus, dev_name,
387               strlen(fbsd_dev_scsi_disk_plus)))
388    goto handlescsi;
389
390  // form /dev/sa* or sa*
391  if (!strncmp(fbsd_dev_scsi_tape1, dev_name,
392    strlen(fbsd_dev_scsi_tape1)))
393    goto handlescsi;
394
395  // form /dev/nsa* or nsa*
396  if (!strncmp(fbsd_dev_scsi_tape2, dev_name,
397    strlen(fbsd_dev_scsi_tape2)))
398    goto handlescsi;
399
400  // form /dev/esa* or esa*
401  if (!strncmp(fbsd_dev_scsi_tape3, dev_name,
402    strlen(fbsd_dev_scsi_tape3)))
403    goto handlescsi;
404
405  if (!strncmp(fbsd_dev_twa_ctrl,dev_name,
406    strlen(fbsd_dev_twa_ctrl))) 
407  {
408    if (chan != NULL) {
409      if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
410        return CONTROLLER_UNKNOWN;
411      }
412    }
413    else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
414      return CONTROLLER_UNKNOWN;
415    }
416    return CONTROLLER_3WARE_9000_CHAR;
417  }
418
419  if (!strncmp(fbsd_dev_twe_ctrl,dev_name,
420        strlen(fbsd_dev_twe_ctrl))) 
421  {
422    if (chan != NULL) {
423      if (get_tw_channel_unit(dev_name,&(chan->channel),&(chan->device))<0) {
424        return CONTROLLER_UNKNOWN;
425      }
426    }
427    else if (get_tw_channel_unit(dev_name,NULL,NULL)<0) {
428      return CONTROLLER_UNKNOWN;
429    }
430    return CONTROLLER_3WARE_678K_CHAR;
431  }
432
433  if (hpt_hba(dev_name)) {
434    return CONTROLLER_HPT;
435  }
436
437  // form /dev/ciss*
438  if (!strncmp(fbsd_dev_cciss, dev_name, strlen(fbsd_dev_cciss)))
439    return CONTROLLER_CCISS;
440
441  // we failed to recognize any of the forms
442  return CONTROLLER_UNKNOWN;
443
444 handlescsi:
445  if (chan != NULL) {
446    if (!(chan->devname = (char *)calloc(1,DEV_IDLEN+1)))
447      return CONTROLLER_UNKNOWN;
448    if (cam_get_device(dev_name,chan->devname,DEV_IDLEN,&(chan->unitnum)) == -1)
449      return CONTROLLER_UNKNOWN;
450  }
451  return CONTROLLER_SCSI;
452
453}
454
455
456bool freebsd_smart_device::open()
457{
458
459  const char *dev = get_dev_name();
460  struct freebsd_dev_channel *fdchan;
461  int parse_ok, i;
462
463  // Search table for a free entry
464  for (i=0; i<FREEBSD_MAXDEV; i++)
465    if (!devicetable[i])
466    break;
467
468  // If no free entry found, return error.  We have max allowed number
469  // of "file descriptors" already allocated.
470  if (i == FREEBSD_MAXDEV) {
471    errno = EMFILE;
472    return false;
473  }
474
475  fdchan = (struct freebsd_dev_channel *)calloc(1,sizeof(struct freebsd_dev_channel));
476  if (fdchan == NULL) {
477    // errno already set by call to malloc()
478    return false;
479  }
480
481  parse_ok = parse_ata_chan_dev(dev,fdchan,get_req_type());
482
483  if (parse_ok == CONTROLLER_UNKNOWN) {
484    free(fdchan);
485    errno = ENOTTY;
486    return false; // can't handle what we don't know
487  }
488
489  if (parse_ok == CONTROLLER_ATA) {
490#ifdef IOCATAREQUEST
491    if ((fdchan->device = ::open(dev,O_RDONLY))<0) {
492#else
493    if ((fdchan->atacommand = ::open("/dev/ata",O_RDWR))<0) {
494#endif
495      int myerror = errno; // preserve across free call
496      free(fdchan);
497      errno = myerror;
498      return false;
499    }
500  }
501  if (parse_ok == CONTROLLER_ATACAM || parse_ok == CONTROLLER_SCSI) {
502    if ((fdchan->camdev = ::cam_open_device(dev,O_RDWR)) == NULL) {
503      perror("cam_open_device");
504      free(fdchan);
505      errno = ENOENT;
506      return false;
507    }
508  }
509
510  if (parse_ok == CONTROLLER_3WARE_678K_CHAR) {
511    char buf[512];
512    sprintf(buf,"/dev/twe%d",fdchan->device);
513#ifdef IOCATAREQUEST
514    if ((fdchan->device = ::open(buf,O_RDWR))<0) {
515#else
516    if ((fdchan->atacommand = ::open(buf,O_RDWR))<0) {
517#endif
518      int myerror = errno; // preserve across free call
519      free(fdchan);
520      errno = myerror;
521      return false;
522    }
523  }
524
525  if (parse_ok == CONTROLLER_3WARE_9000_CHAR) {
526    char buf[512];
527    sprintf(buf,"/dev/twa%d",fdchan->device);
528#ifdef IOCATAREQUEST
529    if ((fdchan->device = ::open(buf,O_RDWR))<0) {
530#else
531    if ((fdchan->atacommand = ::open(buf,O_RDWR))<0) {
532#endif
533      int myerror = errno; // preserve across free call
534      free(fdchan);
535      errno = myerror;
536      return false;
537    }
538  }
539
540  if (parse_ok == CONTROLLER_HPT) {
541    if ((fdchan->device = ::open(dev,O_RDWR))<0) {
542      int myerror = errno; // preserve across free call
543      free(fdchan);
544      errno = myerror;
545      return false;
546    }
547  }
548
549  if (parse_ok == CONTROLLER_CCISS) {
550    if ((fdchan->device = ::open(dev,O_RDWR))<0) {
551      int myerror = errno; // preserve across free call
552      free(fdchan);
553      errno = myerror;
554      return false;
555    }
556  }
557
558  // return pointer to "file descriptor" table entry, properly offset.
559  devicetable[i]=fdchan;
560  m_fd = i+FREEBSD_FDOFFSET;
561  // endofold
562  if (m_fd < 0) {
563    set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
564    return false;
565  }
566  return true;
567}
568
569bool freebsd_smart_device::close()
570{
571  int fd = m_fd; m_fd = -1;
572  struct freebsd_dev_channel *fdchan;
573  int failed = 0;
574
575  // check for valid file descriptor
576  if (isnotopen(&fd, &fdchan))
577    return false;
578
579  // did we allocate a SCSI device name?
580  if (fdchan->devname)
581    free(fdchan->devname);
582
583  // close device, if open
584  if (fdchan->device)
585    failed=::close(fdchan->device);
586#ifndef IOCATAREQUEST
587  if (fdchan->atacommand)
588    failed=::close(fdchan->atacommand);
589#endif
590
591  if (fdchan->camdev != NULL)
592    cam_close_device(fdchan->camdev);
593
594  // if close succeeded, then remove from device list
595  // Eduard, should we also remove it from list if close() fails?  I'm
596  // not sure. Here I only remove it from list if close() worked.
597  if (!failed) {
598    free(fdchan);
599    devicetable[fd]=NULL;
600  }
601  if(failed) return false;
602  else return true;
603}
604
605/////////////////////////////////////////////////////////////////////////////
606/// Implement standard ATA support with old functions
607
608class freebsd_ata_device
609: public /*implements*/ ata_device_with_command_set,
610  public /*extends*/ freebsd_smart_device
611{
612public:
613  freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
614
615#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
616  virtual bool ata_identify_is_cached() const;
617#endif
618
619protected:
620  virtual int ata_command_interface(smart_command_set command, int select, char * data);
621
622  #ifdef IOCATAREQUEST
623        virtual int do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request);
624  #endif
625};
626
627freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
628: smart_device(intf, dev_name, "ata", req_type),
629  freebsd_smart_device("ATA")
630{
631}
632
633int freebsd_ata_device::do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request)
634{
635  return ioctl(con->device, IOCATAREQUEST, request);
636}
637
638#if FREEBSDVER > 800100
639class freebsd_atacam_device : public freebsd_ata_device
640{
641public:
642  freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type)
643  : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type)
644  {}
645
646protected:
647        virtual int do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request);
648};
649
650int freebsd_atacam_device::do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request)
651{
652  union ccb ccb;
653  int camflags;
654
655  memset(&ccb, 0, sizeof(ccb));
656
657  if (request->count == 0)
658    camflags = CAM_DIR_NONE;
659  else if (request->flags == ATA_CMD_READ)
660    camflags = CAM_DIR_IN;
661  else
662    camflags = CAM_DIR_OUT;
663
664  cam_fill_ataio(&ccb.ataio,
665                 0,
666                 NULL,
667                 camflags,
668                 MSG_SIMPLE_Q_TAG,
669                 (u_int8_t*)request->data,
670                 request->count,
671                 request->timeout);
672
673  // ata_28bit_cmd
674  ccb.ataio.cmd.flags = 0;
675  ccb.ataio.cmd.command = request->u.ata.command;
676  ccb.ataio.cmd.features = request->u.ata.feature;
677  ccb.ataio.cmd.lba_low = request->u.ata.lba;
678  ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8;
679  ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16;
680  ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f);
681  ccb.ataio.cmd.sector_count = request->u.ata.count;
682
683  ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
684
685  if (cam_send_ccb(con->camdev, &ccb) < 0) {
686    err(1, "cam_send_ccb");
687    return -1;
688  }
689
690  if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
691    return 0;
692
693  cam_error_print(con->camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
694  return -1;
695}
696
697#endif
698
699int freebsd_ata_device::ata_command_interface(smart_command_set command, int select, char * data)
700{
701 int fd=get_fd();
702#if !defined(ATAREQUEST) && !defined(IOCATAREQUEST)
703 // sorry, but without ATAng, we can't do anything here
704 printwarning(BAD_KERNEL,NULL);
705 errno = ENOSYS;
706 return -1;
707#else
708 struct freebsd_dev_channel* con;
709 int retval, copydata=0;
710#ifdef IOCATAREQUEST
711 struct ata_ioc_request request;
712#else
713 struct ata_cmd iocmd;
714#endif
715 unsigned char buff[512];
716
717 // check that "file descriptor" is valid
718 if (isnotopen(&fd,&con))
719  return -1;
720
721 bzero(buff,512);
722
723#ifdef IOCATAREQUEST
724 bzero(&request,sizeof(struct ata_ioc_request));
725#else
726 bzero(&iocmd,sizeof(struct ata_cmd));
727#endif
728 bzero(buff,512);
729
730#ifndef IOCATAREQUEST
731 iocmd.cmd=ATAREQUEST;
732 iocmd.channel=con->channel;
733 iocmd.device=con->device;
734#define request iocmd.u.request
735#endif
736
737 request.u.ata.command=ATA_SMART_CMD;
738 request.timeout=600;
739 switch (command){
740 case READ_VALUES:
741  request.u.ata.feature=ATA_SMART_READ_VALUES;
742  request.u.ata.lba=0xc24f<<8;
743  request.flags=ATA_CMD_READ;
744  request.data=(char *)buff;
745  request.count=512;
746  copydata=1;
747  break;
748 case READ_THRESHOLDS:
749  request.u.ata.feature=ATA_SMART_READ_THRESHOLDS;
750  request.u.ata.count=1;
751  request.u.ata.lba=1|(0xc24f<<8);
752  request.flags=ATA_CMD_READ;
753  request.data=(char *)buff;
754  request.count=512;
755  copydata=1;
756  break;
757 case READ_LOG:
758  request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR;
759  request.u.ata.lba=select|(0xc24f<<8);
760  request.u.ata.count=1;
761  request.flags=ATA_CMD_READ;
762  request.data=(char *)buff;
763  request.count=512;
764  copydata=1;
765  break;
766 case IDENTIFY:
767  request.u.ata.command=ATA_IDENTIFY_DEVICE;
768  request.flags=ATA_CMD_READ;
769  request.data=(char *)buff;
770  request.count=512;
771  copydata=1;
772  break;
773 case PIDENTIFY:
774  request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE;
775  request.flags=ATA_CMD_READ;
776  request.data=(char *)buff;
777  request.count=512;
778  copydata=1;
779  break;
780 case ENABLE:
781  request.u.ata.feature=ATA_SMART_ENABLE;
782  request.u.ata.lba=0xc24f<<8;
783  request.flags=ATA_CMD_CONTROL;
784  break;
785 case DISABLE:
786  request.u.ata.feature=ATA_SMART_DISABLE;
787  request.u.ata.lba=0xc24f<<8;
788  request.flags=ATA_CMD_CONTROL;
789  break;
790 case AUTO_OFFLINE:
791  // NOTE: According to ATAPI 4 and UP, this command is obsolete
792  request.u.ata.feature=ATA_SMART_AUTO_OFFLINE;
793  request.u.ata.lba=0xc24f<<8;                                                                                                                                         
794  request.u.ata.count=select;                                                                                                                                         
795  request.flags=ATA_CMD_CONTROL;
796  break;
797 case AUTOSAVE:
798  request.u.ata.feature=ATA_SMART_AUTOSAVE;
799  request.u.ata.lba=0xc24f<<8;
800  request.u.ata.count=select;
801  request.flags=ATA_CMD_CONTROL;
802  break;
803 case IMMEDIATE_OFFLINE:
804  request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE;
805  request.u.ata.lba = select|(0xc24f<<8); // put test in sector
806  request.flags=ATA_CMD_CONTROL;
807  break;
808 case STATUS_CHECK: // same command, no HDIO in FreeBSD
809 case STATUS:
810  // this command only says if SMART is working.  It could be
811  // replaced with STATUS_CHECK below.
812  request.u.ata.feature=ATA_SMART_STATUS;
813  request.u.ata.lba=0xc24f<<8;
814  request.flags=ATA_CMD_CONTROL;
815  break;
816 case CHECK_POWER_MODE:
817  request.u.ata.command=ATA_CHECK_POWER_MODE;
818  request.u.ata.feature=0;
819  request.flags=ATA_CMD_CONTROL;
820  break;
821 case WRITE_LOG:
822  memcpy(buff, data, 512);
823  request.u.ata.feature=ATA_SMART_WRITE_LOG_SECTOR;
824  request.u.ata.lba=select|(0xc24f<<8);
825  request.u.ata.count=1;
826  request.flags=ATA_CMD_WRITE;
827  request.data=(char *)buff;
828  request.count=512;
829  break;
830 default:
831  pout("Unrecognized command %d in ata_command_interface()\n"
832   "Please contact " PACKAGE_BUGREPORT "\n", command);
833  errno=ENOSYS;
834  return -1;
835 }
836
837 if (command==STATUS_CHECK){
838  unsigned const char normal_lo=0x4f, normal_hi=0xc2;
839  unsigned const char failed_lo=0xf4, failed_hi=0x2c;
840  unsigned char low,high;
841
842#ifdef IOCATAREQUEST
843  if ((retval=do_cmd(con, &request)) || request.error)
844#else
845  if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
846#endif
847  return -1;
848
849#if (FREEBSDVER < 502000)
850  printwarning(NO_RETURN,NULL);
851#endif
852
853  high = (request.u.ata.lba >> 16) & 0xff;
854  low = (request.u.ata.lba >> 8) & 0xff;
855
856  // Cyl low and Cyl high unchanged means "Good SMART status"
857  if (low==normal_lo && high==normal_hi)
858   return 0;
859
860  // These values mean "Bad SMART status"
861  if (low==failed_lo && high==failed_hi)
862   return 1;
863
864  // We haven't gotten output that makes sense; print out some debugging info
865  char buf[512];
866  sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
867   (int)request.u.ata.command,
868   (int)request.u.ata.feature,
869   (int)request.u.ata.count,
870   (int)((request.u.ata.lba) & 0xff),
871   (int)((request.u.ata.lba>>8) & 0xff),
872   (int)((request.u.ata.lba>>16) & 0xff),
873   (int)request.error);
874  printwarning(BAD_SMART,buf);
875  return 0;   
876 }
877
878#ifdef IOCATAREQUEST
879 if ((retval=do_cmd(con, &request)) || request.error)
880#else
881 if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error)
882#endif
883 {
884  return -1;
885 }
886 //
887 if (command == CHECK_POWER_MODE) {
888  data[0] = request.u.ata.count & 0xff;
889  return 0;
890 }
891 if (copydata)
892  memcpy(data, buff, 512);
893
894 return 0;
895#endif
896}
897
898#ifdef HAVE_ATA_IDENTIFY_IS_CACHED
899bool freebsd_ata_device::ata_identify_is_cached() const
900{
901  return !!::ata_identify_is_cached(get_fd());
902}
903#endif
904
905
906/////////////////////////////////////////////////////////////////////////////
907/// Implement AMCC/3ware RAID support with old functions
908
909class freebsd_escalade_device
910: public /*implements*/ ata_device_with_command_set,
911  public /*extends*/ freebsd_smart_device
912{
913public:
914  freebsd_escalade_device(smart_interface * intf, const char * dev_name,
915    int escalade_type, int disknum);
916
917protected:
918  virtual int ata_command_interface(smart_command_set command, int select, char * data);
919
920private:
921  int m_escalade_type; ///< Type string for escalade_command_interface().
922  int m_disknum; ///< Disk number.
923};
924
925freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name,
926    int escalade_type, int disknum)
927: smart_device(intf, dev_name, "3ware", "3ware"),
928  freebsd_smart_device(
929    escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" :
930    escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" :
931    /*             CONTROLLER_3WARE_678K     */ "ATA"             ),
932  m_escalade_type(escalade_type), m_disknum(disknum)
933{
934  set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum);
935}
936
937int freebsd_escalade_device::ata_command_interface(smart_command_set command, int select, char * data)
938{
939  // to hold true file descriptor
940  int fd = get_fd();
941  struct freebsd_dev_channel* con;
942
943  // return value and buffer for ioctl()
944  int  ioctlreturn, readdata=0;
945  struct twe_usercommand* cmd_twe = NULL;
946  TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL;
947  TWE_Command_ATA* ata = NULL;
948
949  // Used by both the SCSI and char interfaces
950  char ioctl_buffer[TW_IOCTL_BUFFER_SIZE];
951
952  if (m_disknum < 0) {
953    printwarning(NO_DISK_3WARE,NULL);
954    return -1;
955  }
956
957  // check that "file descriptor" is valid
958  if (isnotopen(&fd,&con))
959    return -1;
960
961  memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE);
962
963  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
964    cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer;
965    cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf;
966    cmd_twa->driver_pkt.buffer_length = 512;
967    ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k;
968  } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
969    cmd_twe = (struct twe_usercommand*)ioctl_buffer;
970    ata = &cmd_twe->tu_command.ata;
971  } else {
972    pout("Unrecognized escalade_type %d in freebsd_3ware_command_interface(disk %d)\n"
973      "Please contact " PACKAGE_BUGREPORT "\n", m_escalade_type, m_disknum);
974    errno=ENOSYS;
975    return -1;
976  }
977
978  ata->opcode = TWE_OP_ATA_PASSTHROUGH;
979
980  // Same for (almost) all commands - but some reset below
981  ata->request_id    = 0xFF;
982  ata->unit          = m_disknum;
983  ata->status        = 0;           
984  ata->flags         = 0x1;
985  ata->drive_head    = 0x0;
986  ata->sector_num    = 0;
987
988  // All SMART commands use this CL/CH signature.  These are magic
989  // values from the ATA specifications.
990  ata->cylinder_lo   = 0x4F;
991  ata->cylinder_hi   = 0xC2;
992
993  // SMART ATA COMMAND REGISTER value
994  ata->command       = ATA_SMART_CMD;
995
996  // Is this a command that reads or returns 512 bytes?
997  // passthru->param values are:
998  // 0x0 - non data command without TFR write check,
999  // 0x8 - non data command with TFR write check,
1000  // 0xD - data command that returns data to host from device
1001  // 0xF - data command that writes data from host to device
1002  // passthru->size values are 0x5 for non-data and 0x07 for data
1003  if (command == READ_VALUES     ||
1004      command == READ_THRESHOLDS ||
1005      command == READ_LOG        ||
1006      command == IDENTIFY        ||
1007      command == WRITE_LOG ) 
1008  {
1009    readdata=1;
1010    if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) {
1011      cmd_twe->tu_data = data;
1012      cmd_twe->tu_size = 512;
1013    }
1014    ata->sgl_offset = 0x5;
1015    ata->size         = 0x5;
1016    ata->param        = 0xD;
1017    ata->sector_count = 0x1;
1018    // For 64-bit to work correctly, up the size of the command packet
1019    // in dwords by 1 to account for the 64-bit single sgl 'address'
1020    // field. Note that this doesn't agree with the typedefs but it's
1021    // right (agree with kernel driver behavior/typedefs).
1022    //if (sizeof(long)==8)
1023    //  ata->size++;
1024  }
1025  else {
1026    // Non data command -- but doesn't use large sector
1027    // count register values. 
1028    ata->sgl_offset = 0x0;
1029    ata->size         = 0x5;
1030    ata->param        = 0x8;
1031    ata->sector_count = 0x0;
1032  }
1033
1034  // Now set ATA registers depending upon command
1035  switch (command){
1036  case CHECK_POWER_MODE:
1037    ata->command     = ATA_CHECK_POWER_MODE;
1038    ata->features    = 0;
1039    ata->cylinder_lo = 0;
1040    ata->cylinder_hi = 0;
1041    break;
1042  case READ_VALUES:
1043    ata->features = ATA_SMART_READ_VALUES;
1044    break;
1045  case READ_THRESHOLDS:
1046    ata->features = ATA_SMART_READ_THRESHOLDS;
1047    break;
1048  case READ_LOG:
1049    ata->features = ATA_SMART_READ_LOG_SECTOR;
1050    // log number to return
1051    ata->sector_num  = select;
1052    break;
1053  case WRITE_LOG:
1054    readdata=0;
1055    ata->features     = ATA_SMART_WRITE_LOG_SECTOR;
1056    ata->sector_count = 1;
1057    ata->sector_num   = select;
1058    ata->param        = 0xF;  // PIO data write
1059    break;
1060  case IDENTIFY:
1061    // ATA IDENTIFY DEVICE
1062    ata->command     = ATA_IDENTIFY_DEVICE;
1063    ata->features    = 0;
1064    ata->cylinder_lo = 0;
1065    ata->cylinder_hi = 0;
1066    break;
1067  case PIDENTIFY:
1068    // 3WARE controller can NOT have packet device internally
1069    pout("WARNING - NO DEVICE FOUND ON 3WARE CONTROLLER (disk %d)\n", m_disknum);
1070    errno=ENODEV;
1071    return -1;
1072  case ENABLE:
1073    ata->features = ATA_SMART_ENABLE;
1074    break;
1075  case DISABLE:
1076    ata->features = ATA_SMART_DISABLE;
1077    break;
1078  case AUTO_OFFLINE:
1079    ata->features     = ATA_SMART_AUTO_OFFLINE;
1080    // Enable or disable?
1081    ata->sector_count = select;
1082    break;
1083  case AUTOSAVE:
1084    ata->features     = ATA_SMART_AUTOSAVE;
1085    // Enable or disable?
1086    ata->sector_count = select;
1087    break;
1088  case IMMEDIATE_OFFLINE:
1089    ata->features    = ATA_SMART_IMMEDIATE_OFFLINE;
1090    // What test type to run?
1091    ata->sector_num  = select;
1092    break;
1093  case STATUS_CHECK:
1094    ata->features = ATA_SMART_STATUS;
1095    break;
1096  case STATUS:
1097    // This is JUST to see if SMART is enabled, by giving SMART status
1098    // command. But it doesn't say if status was good, or failing.
1099    // See below for the difference.
1100    ata->features = ATA_SMART_STATUS;
1101    break;
1102  default:
1103    pout("Unrecognized command %d in freebsd_3ware_command_interface(disk %d)\n"
1104         "Please contact " PACKAGE_BUGREPORT "\n", command, m_disknum);
1105    errno=ENOSYS;
1106    return -1;
1107  }
1108
1109  // Now send the command down through an ioctl()
1110  if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) {
1111#ifdef IOCATAREQUEST
1112    ioctlreturn=ioctl(con->device,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
1113#else
1114    ioctlreturn=ioctl(con->atacommand,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa);
1115#endif
1116  } else {
1117#ifdef IOCATAREQUEST
1118    ioctlreturn=ioctl(con->device,TWEIO_COMMAND,cmd_twe);
1119#else
1120    ioctlreturn=ioctl(con->atacommand,TWEIO_COMMAND,cmd_twe);
1121#endif
1122  }
1123
1124  // Deal with the different error cases
1125  if (ioctlreturn) {
1126    if (!errno)
1127      errno=EIO;
1128    return -1;
1129  }
1130
1131  // See if the ATA command failed.  Now that we have returned from
1132  // the ioctl() call, if passthru is valid, then:
1133  // - ata->status contains the 3ware controller STATUS
1134  // - ata->command contains the ATA STATUS register
1135  // - ata->features contains the ATA ERROR register
1136  //
1137  // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS
1138  // If bit 0 (error bit) is set, then ATA ERROR register is valid.
1139  // While we *might* decode the ATA ERROR register, at the moment it
1140  // doesn't make much sense: we don't care in detail why the error
1141  // happened.
1142
1143  if (ata->status || (ata->command & 0x21)) {
1144    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);
1145    errno=EIO;
1146    return -1;
1147  }
1148
1149  // If this is a read data command, copy data to output buffer
1150  if (readdata) {
1151    if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR)
1152      memcpy(data, cmd_twa->pdata, 512);
1153  }
1154
1155  // For STATUS_CHECK, we need to check register values
1156  if (command==STATUS_CHECK) {
1157
1158    // To find out if the SMART RETURN STATUS is good or failing, we
1159    // need to examine the values of the Cylinder Low and Cylinder
1160    // High Registers.
1161
1162    unsigned short cyl_lo=ata->cylinder_lo;
1163    unsigned short cyl_hi=ata->cylinder_hi;
1164
1165    // If values in Cyl-LO and Cyl-HI are unchanged, SMART status is good.
1166    if (cyl_lo==0x4F && cyl_hi==0xC2)
1167      return 0;
1168
1169    // If values in Cyl-LO and Cyl-HI are as follows, SMART status is FAIL
1170    if (cyl_lo==0xF4 && cyl_hi==0x2C)
1171      return 1;
1172
1173      errno=EIO;
1174      return -1;
1175  }
1176
1177  // copy sector count register (one byte!) to return data
1178  if (command==CHECK_POWER_MODE)
1179    *data=*(char *)&(ata->sector_count);
1180
1181  // look for nonexistent devices/ports
1182  if (command==IDENTIFY && !nonempty((unsigned char *)data, 512)) {
1183    errno=ENODEV;
1184    return -1;
1185  }
1186
1187  return 0;
1188}
1189
1190
1191/////////////////////////////////////////////////////////////////////////////
1192/// Implement Highpoint RAID support with old functions
1193
1194class freebsd_highpoint_device
1195: public /*implements*/ ata_device_with_command_set,
1196  public /*extends*/ freebsd_smart_device
1197{
1198public:
1199  freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
1200    unsigned char controller, unsigned char channel, unsigned char port);
1201
1202protected:
1203  virtual int ata_command_interface(smart_command_set command, int select, char * data);
1204
1205private:
1206  unsigned char m_hpt_data[3]; ///< controller/channel/port
1207};
1208
1209
1210freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name,
1211  unsigned char controller, unsigned char channel, unsigned char port)
1212: smart_device(intf, dev_name, "hpt", "hpt"),
1213  freebsd_smart_device("ATA")
1214{
1215  m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port;
1216  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]);
1217}
1218
1219int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data)
1220{
1221  int fd=get_fd(); 
1222  int ids[2];
1223  struct freebsd_dev_channel* fbcon;
1224  HPT_IOCTL_PARAM param;
1225  HPT_CHANNEL_INFO_V2 info;
1226  unsigned char* buff[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)];
1227  PHPT_PASS_THROUGH_HEADER pide_pt_hdr, pide_pt_hdr_out;
1228
1229  // check that "file descriptor" is valid
1230  if (isnotopen(&fd, &fbcon))
1231    return -1;
1232
1233  // get internal deviceid
1234  ids[0] = m_hpt_data[0] - 1;
1235  ids[1] = m_hpt_data[1] - 1;
1236
1237  memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
1238
1239  param.magic = HPT_IOCTL_MAGIC;
1240  param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO_V2;
1241  param.in = (unsigned char *)ids;
1242  param.in_size = sizeof(unsigned int) * 2;
1243  param.out = (unsigned char *)&info;
1244  param.out_size = sizeof(HPT_CHANNEL_INFO_V2);
1245
1246  if (m_hpt_data[2]==1) {
1247    param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO;
1248    param.out_size = sizeof(HPT_CHANNEL_INFO);
1249  }
1250  if (ioctl(fbcon->device, HPT_DO_IOCONTROL, &param)!=0 ||
1251      info.devices[m_hpt_data[2]-1]==0) {
1252    return -1;
1253  }
1254
1255  // perform smart action
1256  memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER));
1257  pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff;
1258
1259  pide_pt_hdr->lbamid = 0x4f;
1260  pide_pt_hdr->lbahigh = 0xc2;
1261  pide_pt_hdr->command = ATA_SMART_CMD;
1262  pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1];
1263
1264  switch (command){
1265  case READ_VALUES:
1266    pide_pt_hdr->feature=ATA_SMART_READ_VALUES;
1267    pide_pt_hdr->protocol=HPT_READ;
1268    break;
1269  case READ_THRESHOLDS:
1270    pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS;
1271    pide_pt_hdr->protocol=HPT_READ;
1272    break;
1273  case READ_LOG:
1274    pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR;
1275    pide_pt_hdr->lbalow=select;
1276    pide_pt_hdr->protocol=HPT_READ;
1277    break;
1278  case IDENTIFY:
1279    pide_pt_hdr->command=ATA_IDENTIFY_DEVICE;
1280    pide_pt_hdr->protocol=HPT_READ;
1281    break;
1282  case ENABLE:
1283    pide_pt_hdr->feature=ATA_SMART_ENABLE;
1284    break;
1285  case DISABLE:
1286    pide_pt_hdr->feature=ATA_SMART_DISABLE;
1287    break;
1288  case AUTO_OFFLINE:
1289    pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE;
1290    pide_pt_hdr->sectorcount=select;
1291    break;
1292  case AUTOSAVE:
1293    pide_pt_hdr->feature=ATA_SMART_AUTOSAVE;
1294    pide_pt_hdr->sectorcount=select;
1295    break;
1296  case IMMEDIATE_OFFLINE:
1297    pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE;
1298    pide_pt_hdr->lbalow=select;
1299    break;
1300  case STATUS_CHECK:
1301  case STATUS:
1302    pide_pt_hdr->feature=ATA_SMART_STATUS;
1303    break;
1304  case CHECK_POWER_MODE:
1305    pide_pt_hdr->command=ATA_CHECK_POWER_MODE;
1306    break;
1307  case WRITE_LOG:
1308    memcpy(buff+sizeof(HPT_PASS_THROUGH_HEADER), data, 512);
1309    pide_pt_hdr->feature=ATA_SMART_WRITE_LOG_SECTOR;
1310    pide_pt_hdr->lbalow=select;
1311    pide_pt_hdr->protocol=HPT_WRITE;
1312    break;
1313  default:
1314    pout("Unrecognized command %d in highpoint_command_interface()\n"
1315         "Please contact " PACKAGE_BUGREPORT "\n", command);
1316    errno=ENOSYS;
1317    return -1;
1318  }
1319  if (pide_pt_hdr->protocol!=0) {
1320    pide_pt_hdr->sectors = 1;
1321    pide_pt_hdr->sectorcount = 1;
1322  }
1323
1324  memset(&param, 0, sizeof(HPT_IOCTL_PARAM));
1325
1326  param.magic = HPT_IOCTL_MAGIC;
1327  param.ctrl_code = HPT_IOCTL_IDE_PASS_THROUGH;
1328  param.in = (unsigned char *)buff;
1329  param.in_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? 0 : pide_pt_hdr->sectors * 512);
1330  param.out = (unsigned char *)buff+param.in_size;
1331  param.out_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? pide_pt_hdr->sectors * 512 : 0);
1332
1333  pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out;
1334
1335  if ((ioctl(fbcon->device, HPT_DO_IOCONTROL, &param)!=0) ||
1336      (pide_pt_hdr_out->command & 1)) {
1337    return -1;
1338  }
1339
1340  if (command==STATUS_CHECK)
1341  {
1342    unsigned const char normal_lo=0x4f, normal_hi=0xc2;
1343    unsigned const char failed_lo=0xf4, failed_hi=0x2c;
1344    unsigned char low,high;
1345
1346    high = pide_pt_hdr_out->lbahigh;
1347    low = pide_pt_hdr_out->lbamid;
1348
1349    // Cyl low and Cyl high unchanged means "Good SMART status"
1350    if (low==normal_lo && high==normal_hi)
1351      return 0;
1352
1353    // These values mean "Bad SMART status"
1354    if (low==failed_lo && high==failed_hi)
1355      return 1;
1356
1357    // We haven't gotten output that makes sense; print out some debugging info
1358    char buf[512];
1359    sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
1360            (int)pide_pt_hdr_out->command,
1361            (int)pide_pt_hdr_out->feature,
1362            (int)pide_pt_hdr_out->sectorcount,
1363            (int)pide_pt_hdr_out->lbalow,
1364            (int)pide_pt_hdr_out->lbamid,
1365            (int)pide_pt_hdr_out->lbahigh,
1366            (int)pide_pt_hdr_out->sectors);
1367    printwarning(BAD_SMART,buf);
1368  }
1369  else if (command==CHECK_POWER_MODE)
1370    data[0] = pide_pt_hdr_out->sectorcount & 0xff;
1371  else if (pide_pt_hdr->protocol==HPT_READ)
1372    memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER), 
1373      pide_pt_hdr->sectors * 512);
1374  return 0;
1375}
1376
1377
1378/////////////////////////////////////////////////////////////////////////////
1379/// Implement standard SCSI support with old functions
1380
1381class freebsd_scsi_device
1382: public /*implements*/ scsi_device,
1383  public /*extends*/ freebsd_smart_device
1384{
1385public:
1386  freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
1387
1388  virtual smart_device * autodetect_open();
1389
1390  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
1391};
1392
1393freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf,
1394  const char * dev_name, const char * req_type)
1395: smart_device(intf, dev_name, "scsi", req_type),
1396  freebsd_smart_device("SCSI")
1397{
1398}
1399
1400// Interface to SCSI devices.  See os_linux.c
1401int do_normal_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report)
1402{
1403  struct freebsd_dev_channel* con = NULL;
1404  union ccb *ccb;
1405
1406  if (report > 0) {
1407    unsigned int k;
1408    const unsigned char * ucp = iop->cmnd;
1409    const char * np;
1410
1411    np = scsi_get_opcode_name(ucp[0]);
1412    pout(" [%s: ", np ? np : "<unknown opcode>");
1413    for (k = 0; k < iop->cmnd_len; ++k)
1414      pout("%02x ", ucp[k]);
1415    if ((report > 1) && 
1416      (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) {
1417    int trunc = (iop->dxfer_len > 256) ? 1 : 0;
1418
1419    pout("]\n  Outgoing data, len=%d%s:\n", (int)iop->dxfer_len,
1420      (trunc ? " [only first 256 bytes shown]" : ""));
1421    dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
1422      }
1423      else
1424        pout("]");
1425  }
1426
1427  // check that "file descriptor" is valid
1428  if (isnotopen(&fd,&con))
1429    return -ENOTTY;
1430
1431  if(con->camdev==NULL) {
1432    warnx("error: con->camdev=0!");
1433    return -ENOTTY;
1434  }
1435
1436  if (!(ccb = cam_getccb(con->camdev))) {
1437    warnx("error allocating ccb");
1438    return -ENOMEM;
1439  }
1440
1441  // clear out structure, except for header that was filled in for us
1442  bzero(&(&ccb->ccb_h)[1],
1443    sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
1444
1445  cam_fill_csio(&ccb->csio,
1446    /*retrires*/ 1,
1447    /*cbfcnp*/ NULL,
1448    /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)),
1449    /* tagaction */ MSG_SIMPLE_Q_TAG,
1450    /* dataptr */ iop->dxferp,
1451    /* datalen */ iop->dxfer_len,
1452    /* senselen */ iop->max_sense_len,
1453    /* cdblen */ iop->cmnd_len,
1454    /* timout (converted to seconds) */ iop->timeout*1000);
1455  memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len);
1456
1457  if (cam_send_ccb(con->camdev,ccb) < 0) {
1458    warn("error sending SCSI ccb");
1459#if (FREEBSDVER > 500000)
1460    cam_error_print(con->camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
1461#endif
1462    cam_freeccb(ccb);
1463    return -EIO;
1464  }
1465
1466  if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) {
1467#if (FREEBSDVER > 500000)
1468    cam_error_print(con->camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
1469#endif
1470    cam_freeccb(ccb);
1471    return -EIO;
1472  }
1473
1474  if (iop->sensep) {
1475    memcpy(iop->sensep,&(ccb->csio.sense_data),sizeof(struct scsi_sense_data));
1476    iop->resp_sense_len = sizeof(struct scsi_sense_data);
1477  }
1478
1479  iop->scsi_status = ccb->csio.scsi_status;
1480
1481  cam_freeccb(ccb);
1482
1483  if (report > 0) {
1484    int trunc;
1485
1486    pout("  status=0\n");
1487    trunc = (iop->dxfer_len > 256) ? 1 : 0;
1488
1489    pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
1490      (trunc ? " [only first 256 bytes shown]" : ""));
1491    dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
1492  }
1493  return 0;
1494}
1495
1496
1497/* Check and call the right interface. Maybe when the do_generic_scsi_cmd_io interface is better
1498   we can take off this crude way of calling the right interface */
1499int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report)
1500{
1501  struct freebsd_dev_channel *fdchan;
1502  switch(m_controller_type)
1503  {
1504  case CONTROLLER_CCISS:
1505#ifdef HAVE_DEV_CISS_CISSIO_H
1506    // check that "file descriptor" is valid
1507    if (isnotopen(&dev_fd,&fdchan))
1508      return -ENOTTY;
1509
1510    return cciss_io_interface(fdchan->device, m_controller_port-1, iop, report);
1511#else
1512    {
1513      static int warned = 0;
1514      if (!warned) {
1515        pout("CCISS support is not available in this build of smartmontools,\n"
1516          "/usr/src/sys/dev/ciss/cissio.h was not available at build time.\n\n");
1517        warned = 1;
1518      }
1519    }
1520    return -ENOSYS;
1521#endif
1522// not reached
1523    break;
1524
1525  default:
1526    return do_normal_scsi_cmnd_io(dev_fd, iop, report);
1527    // not reached
1528    break;
1529  }
1530}
1531
1532bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
1533{
1534  unsigned char oldtype = m_controller_type, oldport = m_controller_port;
1535  m_controller_type = CONTROLLER_SCSI; m_controller_port = 0;
1536  int status = do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
1537  m_controller_type = oldtype; m_controller_port = oldport;
1538  if (status < 0) {
1539    set_err(-status);
1540    return false;
1541  }
1542  return true;
1543}
1544
1545
1546/////////////////////////////////////////////////////////////////////////////
1547/// Implement CCISS RAID support with old functions
1548
1549class freebsd_cciss_device
1550: public /*implements*/ scsi_device,
1551  public /*extends*/ freebsd_smart_device
1552{
1553public:
1554  freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum);
1555
1556  virtual bool scsi_pass_through(scsi_cmnd_io * iop);
1557
1558private:
1559  unsigned char m_disknum; ///< Disk number.
1560};
1561
1562
1563freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf,
1564  const char * dev_name, unsigned char disknum)
1565: smart_device(intf, dev_name, "cciss", "cciss"),
1566  freebsd_smart_device("SCSI"),
1567  m_disknum(disknum)
1568{
1569  set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum);
1570}
1571
1572bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop)
1573{
1574  // See os_linux.cpp
1575  unsigned char oldtype = m_controller_type, oldport = m_controller_port;
1576  m_controller_type = CONTROLLER_CCISS; m_controller_port = m_disknum+1;
1577  int status = do_scsi_cmnd_io(get_fd(), iop, con->reportscsiioctl);
1578  m_controller_type = oldtype; m_controller_port = oldport;
1579  if (status < 0) {
1580      set_err(-status);
1581      return false;
1582  }
1583  return true;
1584}
1585
1586
1587/////////////////////////////////////////////////////////////////////////////
1588/// SCSI open with autodetection support
1589
1590smart_device * freebsd_scsi_device::autodetect_open()
1591{
1592  // Open device
1593  if (!open())
1594    return this;
1595
1596  // No Autodetection if device type was specified by user
1597  if (*get_req_type())
1598    return this;
1599
1600  // The code below is based on smartd.cpp:SCSIFilterKnown()
1601
1602  // Get INQUIRY
1603  unsigned char req_buff[64] = {0, };
1604  int req_len = 36;
1605  if (scsiStdInquiry(this, req_buff, req_len)) {
1606    // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
1607    // watch this spot ... other devices could lock up here
1608    req_len = 64;
1609    if (scsiStdInquiry(this, req_buff, req_len)) {
1610      // device doesn't like INQUIRY commands
1611      close();
1612      set_err(EIO, "INQUIRY failed");
1613      return this;
1614    }
1615  }
1616
1617  int avail_len = req_buff[4] + 5;
1618  int len = (avail_len < req_len ? avail_len : req_len);
1619  if (len < 36)
1620    return this;
1621
1622  // Use INQUIRY to detect type
1623  smart_device * newdev = 0;
1624  try {
1625    // 3ware ?
1626    if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
1627      close();
1628      set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
1629                      "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
1630      return this;
1631    }
1632
1633    // SAT or USB ?
1634    newdev = smi()->autodetect_sat_device(this, req_buff, len);
1635    if (newdev)
1636      // NOTE: 'this' is now owned by '*newdev'
1637      return newdev;
1638  }
1639  catch (...) {
1640    // Cleanup if exception occurs after newdev was allocated
1641    delete newdev;
1642    throw;
1643  }
1644
1645  // Nothing special found
1646  return this;
1647}
1648
1649
1650/////////////////////////////////////////////////////////////////////////////
1651/// Implement platform interface with old functions.
1652
1653class freebsd_smart_interface
1654: public /*implements*/ smart_interface
1655{
1656public:
1657  virtual std::string get_os_version_str();
1658
1659  virtual std::string get_app_examples(const char * appname);
1660
1661  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
1662    const char * pattern = 0);
1663
1664protected:
1665  virtual ata_device * get_ata_device(const char * name, const char * type);
1666
1667  virtual ata_device * get_atacam_device(const char * name, const char * type);
1668
1669  virtual scsi_device * get_scsi_device(const char * name, const char * type);
1670
1671  virtual smart_device * autodetect_smart_device(const char * name);
1672
1673  virtual smart_device * get_custom_smart_device(const char * name, const char * type);
1674
1675  virtual std::string get_valid_custom_dev_types_str();
1676};
1677
1678
1679//////////////////////////////////////////////////////////////////////
1680
1681std::string freebsd_smart_interface::get_os_version_str()
1682{
1683  struct utsname osname;
1684  uname(&osname);
1685  return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine);
1686}
1687
1688std::string freebsd_smart_interface::get_app_examples(const char * appname)
1689{
1690  if (!strcmp(appname, "smartctl"))
1691    return smartctl_examples;
1692  return "";
1693}
1694
1695ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type)
1696{
1697  return new freebsd_ata_device(this, name, type);
1698}
1699
1700ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type)
1701{
1702  return new freebsd_atacam_device(this, name, type);
1703}
1704
1705scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type)
1706{
1707  return new freebsd_scsi_device(this, name, type);
1708}
1709
1710static int 
1711cam_get_umassno(char * devname) {
1712  struct cam_device *cam_dev;
1713  union ccb ccb;
1714  int bus=-1;
1715 
1716  // open CAM device
1717  if ((cam_dev = cam_open_device(devname,O_RDWR)) == NULL) {
1718    // open failue
1719    perror("cam_open_device");
1720    return -1;
1721  }
1722 
1723  // zero the payload
1724  bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE);
1725  ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device
1726  if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
1727                warn("Get Transfer Settings CCB failed\n"
1728                        "%s", strerror(errno));
1729    bus=-1;
1730        }
1731  else {
1732    // now check if we are working with USB device, see umass.c
1733    if(strcmp(ccb.cpi.sim_vid,"FreeBSD") == 0 
1734      && strcmp(ccb.cpi.hba_vid,"USB SCSI")==0) {
1735      bus=ccb.cpi.bus_id; // bus_id will match umass number
1736    }
1737  }
1738  // close cam device, we don`t need it anymore
1739  cam_close_device(cam_dev);
1740  return bus;
1741}
1742
1743
1744// we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...)
1745// devices on system despite of it's names
1746//
1747// If any errors occur, leave errno set as it was returned by the
1748// system call, and return <0.
1749//
1750// Return values:
1751// -1:   error
1752// >=0: number of discovered devices
1753
1754int get_dev_names_cam(char*** names) {
1755  int n = 0;
1756  char** mp = NULL;
1757  unsigned int i;
1758  union ccb ccb;
1759  int bufsize, fd = -1;
1760  int skip_device = 0, skip_bus = 0, changed = 0;
1761  char *devname = NULL;
1762  int serrno=-1;
1763
1764  // in case of non-clean exit
1765  *names=NULL;
1766  ccb.cdm.matches = NULL;
1767
1768  if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
1769    if (errno == ENOENT) /* There are no CAM device on this computer */
1770      return 0;
1771    serrno = errno;
1772    pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
1773    n = -1;
1774    goto end;
1775  }
1776
1777  // allocate space for up to MAX_NUM_DEV number of ATA devices
1778  mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
1779  if (mp == NULL) {
1780    serrno=errno;
1781    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
1782    n = -1;
1783    goto end;
1784  };
1785
1786  bzero(&ccb, sizeof(union ccb));
1787
1788  ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
1789  ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1790  ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1791
1792  ccb.ccb_h.func_code = XPT_DEV_MATCH;
1793  bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
1794  ccb.cdm.match_buf_len = bufsize;
1795  ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
1796  if (ccb.cdm.matches == NULL) {
1797    serrno = errno;
1798    pout("can't malloc memory for matches on line %d\n", __LINE__);
1799    n = -1;
1800    goto end;
1801  }
1802  ccb.cdm.num_matches = 0;
1803  ccb.cdm.num_patterns = 0;
1804  ccb.cdm.pattern_buf_len = 0;
1805
1806  /*
1807   * We do the ioctl multiple times if necessary, in case there are
1808   * more than MAX_NUM_DEV nodes in the EDT.
1809   */
1810  do {
1811    if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1812      serrno = errno;
1813      pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
1814      n = -1;
1815      break;
1816    }
1817
1818    if ((ccb.ccb_h.status != CAM_REQ_CMP)
1819      || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
1820      && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
1821      pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
1822      serrno = ENXIO;
1823      n = -1;
1824      goto end;
1825    }
1826
1827    for (i = 0; i < ccb.cdm.num_matches && n < MAX_NUM_DEV; i++) {
1828      struct bus_match_result *bus_result;
1829      struct device_match_result *dev_result;
1830      struct periph_match_result *periph_result;
1831
1832      if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
1833        bus_result = &ccb.cdm.matches[i].result.bus_result;
1834
1835        if (strcmp(bus_result->dev_name,"ata") == 0 /* ATAPICAM devices will be probed as ATA devices, skip'em there */
1836          || strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
1837        skip_bus = 1;
1838        else
1839          skip_bus = 0;
1840        changed = 1;
1841      } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
1842        dev_result = &ccb.cdm.matches[i].result.device_result;
1843
1844        if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
1845          skip_device = 1;
1846        else
1847          skip_device = 0;
1848
1849        //        /* Shall we skip non T_DIRECT devices ? */
1850        //        if (dev_result->inq_data.device != T_DIRECT)
1851        //          skip_device = 1;
1852        changed = 1;
1853      } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && skip_device == 0) { 
1854        /* One device may be populated as many peripherals (pass0 & da0 for example).
1855        * We are searching for latest name
1856        */
1857        periph_result =  &ccb.cdm.matches[i].result.periph_result;
1858        free(devname);
1859        asprintf(&devname, "%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
1860        if (devname == NULL) {
1861          serrno=errno;
1862          pout("Out of memory constructing scan SCSI device list (on line %d)\n", __LINE__);
1863          n = -1;
1864          goto end;
1865        };
1866        changed = 0;
1867      };
1868
1869      if (changed == 1 && devname != NULL) {
1870        mp[n] = devname;
1871        devname = NULL;
1872        bytes+=1+strlen(mp[n]);
1873        n++;
1874        changed = 0;
1875      };
1876    }
1877
1878  } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE) && n < MAX_NUM_DEV);
1879
1880  if (devname != NULL) {
1881    mp[n] = devname;
1882    devname = NULL;
1883    bytes+=1+strlen(mp[n]);
1884    n++;
1885  };
1886
1887  mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
1888  bytes += (n)*(sizeof(char*)); // and set allocated byte count
1889
1890end:
1891  free(ccb.cdm.matches);
1892  if (fd>-1)
1893    close(fd);
1894  if (n <= 0) {
1895    free(mp);
1896    mp = NULL;
1897  }
1898
1899  *names=mp;
1900
1901  if (serrno>-1)
1902    errno=serrno;
1903  return(n);
1904}
1905
1906// we are using ATA subsystem enumerator to found all ATA devices on system
1907// despite of it's names
1908//
1909// If any errors occur, leave errno set as it was returned by the
1910// system call, and return <0.
1911
1912// Return values:
1913// -1:   error
1914// >=0: number of discovered devices
1915int get_dev_names_ata(char*** names) {
1916  struct ata_ioc_devices devices;
1917  int fd=-1,maxchannel,serrno=-1,n=0;
1918  char **mp = NULL;
1919
1920  *names=NULL;
1921
1922  if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
1923    if (errno == ENOENT) /* There are no ATA device on this computer */
1924      return 0;
1925    serrno = errno;
1926    pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
1927    n = -1;
1928    goto end;
1929  };
1930
1931  if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
1932    serrno = errno;
1933    pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
1934    n = -1;
1935    goto end;
1936  };
1937
1938  // allocate space for up to MAX_NUM_DEV number of ATA devices
1939  mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
1940  if (mp == NULL) {
1941    serrno=errno;
1942    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
1943    n = -1;
1944    goto end;
1945  };
1946
1947  for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
1948    int j;
1949
1950    if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
1951      if (errno == ENXIO)
1952        continue; /* such channel not exist */
1953      pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
1954      n = -1;
1955      goto end;
1956    };
1957    for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
1958      if (devices.name[j][0] != '\0') {
1959        asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
1960        if (mp[n] == NULL) {
1961          pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
1962          n = -1;
1963          goto end;
1964        };
1965        bytes+=1+strlen(mp[n]);
1966        n++;
1967      };
1968    };
1969  }; 
1970  mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
1971  bytes += (n)*(sizeof(char*)); // and set allocated byte count
1972
1973end:
1974  if (fd>=0)
1975    close(fd);
1976  if (n <= 0) {
1977    free(mp);
1978    mp = NULL;
1979  }
1980
1981  *names=mp;
1982
1983  if (serrno>-1)
1984    errno=serrno;
1985  return n;
1986}
1987
1988
1989
1990bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
1991  const char * type, const char * pattern /*= 0*/)
1992{
1993  if (pattern) {
1994    set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
1995    return false;
1996  }
1997
1998  // Make namelists
1999  char * * atanames = 0; int numata = 0;
2000  if (!type || !strcmp(type, "ata")) {
2001    numata = get_dev_names_ata(&atanames);
2002    if (numata < 0) {
2003      set_err(ENOMEM);
2004      return false;
2005    }
2006  }
2007
2008  char * * scsinames = 0; int numscsi = 0;
2009  if (!type || !strcmp(type, "scsi")) {
2010    numscsi = get_dev_names_cam(&scsinames);
2011    if (numscsi < 0) {
2012      set_err(ENOMEM);
2013      return false;
2014    }
2015  }
2016
2017  // Add to devlist
2018  int i;
2019  if (type==NULL)
2020    type="";
2021  for (i = 0; i < numata; i++) {
2022    ata_device * atadev = get_ata_device(atanames[i], type);
2023    if (atadev)
2024      devlist.add(atadev);
2025  }
2026
2027  for (i = 0; i < numscsi; i++) {
2028    if(!*type) { // try USB autodetection if no type specified
2029      smart_device * smartdev = autodetect_smart_device(scsinames[i]);
2030      if(smartdev)
2031        devlist.add(smartdev);
2032    }
2033    else {
2034      scsi_device * scsidev = get_scsi_device(scsinames[i], type);
2035      if (scsidev)
2036        devlist.add(scsidev);
2037    }
2038  }
2039  return true;
2040}
2041
2042
2043#if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8
2044static char done[USB_MAX_DEVICES];
2045
2046static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id,
2047  unsigned short & product_id, unsigned short & version)
2048{ 
2049
2050  struct usb_device_info di;
2051  int e, p, i;
2052  char devname[256];
2053
2054  snprintf(devname, sizeof(devname),"umass%d",busno);
2055
2056  di.udi_addr = a;
2057  e = ioctl(f, USB_DEVICEINFO, &di);
2058  if (e) {
2059    if (errno != ENXIO)
2060      printf("addr %d: I/O error\n", a);
2061    return 0;
2062  }
2063  done[a] = 1;
2064
2065  // list devices
2066  for (i = 0; i < USB_MAX_DEVNAMES; i++) {
2067    if (di.udi_devnames[i][0]) {
2068      if(strcmp(di.udi_devnames[i],devname)==0) {
2069        // device found!
2070        vendor_id = di.udi_vendorNo;
2071        product_id = di.udi_productNo;
2072        version = di.udi_releaseNo;
2073        return 1;
2074        // FIXME
2075      }
2076    }
2077  }
2078  if (!rec)
2079    return 0;
2080  for (p = 0; p < di.udi_nports; p++) {
2081    int s = di.udi_ports[p];
2082    if (s >= USB_MAX_DEVICES) {
2083      continue;
2084    }
2085    if (s == 0)
2086      printf("addr 0 should never happen!\n");
2087    else {
2088      if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1;
2089    }
2090  }
2091  return 0;
2092}
2093#endif
2094
2095
2096static int usbdevlist(int busno,unsigned short & vendor_id,
2097  unsigned short & product_id, unsigned short & version)
2098{
2099#if (FREEBSDVER >= 800000) // libusb2 interface
2100  struct libusb20_device *pdev = NULL;
2101  struct libusb20_backend *pbe;
2102  uint32_t matches = 0;
2103  char buf[128]; // do not change!
2104  char devname[128];
2105  uint8_t n;
2106  struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
2107
2108  pbe = libusb20_be_alloc_default();
2109
2110  while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
2111    matches++;
2112
2113    if (libusb20_dev_open(pdev, 0)) {
2114      warnx("libusb20_dev_open: could not open device");
2115      return 0;
2116    }
2117
2118    pdesc=libusb20_dev_get_device_desc(pdev);
2119
2120    snprintf(devname, sizeof(devname),"umass%d:",busno);
2121    for (n = 0; n != 255; n++) {
2122      if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf)))
2123        break;
2124      if (buf[0] == 0)
2125        continue;
2126      if(strncmp(buf,devname,strlen(devname))==0){
2127        // found!
2128        vendor_id = pdesc->idVendor;
2129        product_id = pdesc->idProduct;
2130        version = pdesc->bcdDevice;
2131        libusb20_dev_close(pdev);
2132        libusb20_be_free(pbe);
2133        return 1;
2134      }
2135    }
2136
2137    libusb20_dev_close(pdev);
2138  }
2139
2140  if (matches == 0) {
2141    printf("No device match or lack of permissions.\n");
2142  }
2143
2144  libusb20_be_free(pbe);
2145
2146  return false;
2147#else // freebsd < 8.0 USB stack, ioctl interface
2148
2149  int  i, f, a, rc;
2150  char buf[50];
2151  int ncont;
2152
2153  for (ncont = 0, i = 0; i < 10; i++) {
2154    snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
2155    f = open(buf, O_RDONLY);
2156    if (f >= 0) {
2157      memset(done, 0, sizeof done);
2158      for (a = 1; a < USB_MAX_DEVICES; a++) {
2159        if (!done[a]) {
2160          rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
2161          if(rc) return 1;
2162        }
2163
2164      }
2165      close(f);
2166    } else {
2167      if (errno == ENOENT || errno == ENXIO)
2168        continue;
2169      warn("%s", buf);
2170    }
2171    ncont++;
2172  }
2173  return 0;
2174#endif
2175}
2176
2177// Get USB bridge ID for the CAM device
2178static bool get_usb_id(const char * path, unsigned short & vendor_id,
2179  unsigned short & product_id, unsigned short & version)
2180{
2181  if (strlen(path) < 5)
2182    return false;
2183  int bus = cam_get_umassno((char *)path+5);
2184  if (bus == -1) 
2185    return false;
2186
2187  usbdevlist(bus,vendor_id,
2188    product_id, version);
2189  return true;
2190}
2191
2192
2193smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name)
2194{
2195  int guess = parse_ata_chan_dev(name,NULL,"");
2196  unsigned short vendor_id = 0, product_id = 0, version = 0;
2197
2198  switch (guess) {
2199  case CONTROLLER_ATA : 
2200    return new freebsd_ata_device(this, name, "");
2201  case CONTROLLER_ATACAM : 
2202    return new freebsd_atacam_device(this, name, "");
2203  case CONTROLLER_SCSI: 
2204    // Try to detect possible USB->(S)ATA bridge
2205    if (get_usb_id(name, vendor_id, product_id, version)) {
2206      const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version);
2207      if (!usbtype)
2208        return 0;
2209      // Return SAT/USB device for this type
2210      // (Note: freebsd_scsi_device::autodetect_open() will not be called in this case)
2211      return get_sat_device(usbtype, new freebsd_scsi_device(this, name, ""));
2212    }
2213    // non usb device, handle as normal scsi
2214    return new freebsd_scsi_device(this, name, "");
2215  case CONTROLLER_CCISS:
2216    // device - cciss, but no ID known
2217    set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
2218    return 0;
2219  }
2220  // TODO: Test autodetected device here
2221  return 0;
2222}
2223
2224
2225smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type)
2226{
2227  // 3Ware ?
2228  int disknum = -1, n1 = -1, n2 = -1;
2229  if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
2230    if (n2 != (int)strlen(type)) {
2231      set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer");
2232      return 0;
2233    }
2234    if (!(0 <= disknum && disknum <= 127)) {
2235      set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
2236      return 0;
2237    }
2238    int contr = parse_ata_chan_dev(name,NULL,"");
2239    if (contr != CONTROLLER_3WARE_9000_CHAR && contr != CONTROLLER_3WARE_678K_CHAR)
2240      contr = CONTROLLER_3WARE_678K;
2241    return new freebsd_escalade_device(this, name, contr, disknum);
2242  } 
2243
2244  // Highpoint ?
2245  int controller = -1, channel = -1; disknum = 1;
2246  n1 = n2 = -1; int n3 = -1;
2247  if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
2248    int len = strlen(type);
2249    if (!(n2 == len || n3 == len)) {
2250      set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items");
2251      return 0;
2252    }
2253    if (!(1 <= controller && controller <= 8)) {
2254      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied");
2255      return 0;
2256    }
2257    if (!(1 <= channel && channel <= 8)) {
2258      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied");
2259      return 0;
2260    }
2261    if (!(1 <= disknum && disknum <= 15)) {
2262      set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied");
2263      return 0;
2264    }
2265    return new freebsd_highpoint_device(this, name, controller, channel, disknum);
2266  }
2267
2268  // CCISS ?
2269  disknum = n1 = n2 = -1;
2270  if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
2271    if (n2 != (int)strlen(type)) {
2272      set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer");
2273      return 0;
2274    }
2275    if (!(0 <= disknum && disknum <= 15)) {
2276      set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 15", disknum);
2277      return 0;
2278    }
2279    return new freebsd_cciss_device(this, name, disknum);
2280  }
2281
2282  return 0;
2283}
2284
2285std::string freebsd_smart_interface::get_valid_custom_dev_types_str()
2286{
2287  return "3ware,N, hpt,L/M/N, cciss,N";
2288}
2289
2290} // namespace
2291
2292/////////////////////////////////////////////////////////////////////////////
2293/// Initialize platform interface and register with smi()
2294
2295void smart_interface::init()
2296{
2297  static os_freebsd::freebsd_smart_interface the_interface;
2298  smart_interface::set(&the_interface);
2299}
Note: See TracBrowser for help on using the browser.