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