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