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