diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG index 4ae0848862245a4f466bb0783d3664692063ef16..9cbea76cd1be53ea2ee48e29b8e5b538e69ee223 100644 --- a/smartmontools/CHANGELOG +++ b/smartmontools/CHANGELOG @@ -43,6 +43,8 @@ NOTES FOR FUTURE RELEASES: see TODO file. <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE> + [AS] FreeBSD: added support for the ada disks, based on agapon patch + [CF] Add names for attributes 184 and 188, see ticket #17. [CF] configure.in: Change configure date syntax. diff --git a/smartmontools/os_freebsd.cpp b/smartmontools/os_freebsd.cpp index b433648200089d2b6cf16ef6918e848eba6220ad..e5ce4ec3fa34991346905ad26b5345f89e3065ba 100644 --- a/smartmontools/os_freebsd.cpp +++ b/smartmontools/os_freebsd.cpp @@ -67,11 +67,12 @@ #define CONTROLLER_UNKNOWN 0x00 #define CONTROLLER_ATA 0x01 #define CONTROLLER_SCSI 0x02 -#define CONTROLLER_3WARE_678K 0x04 // NOT set by guess_device_type() -#define CONTROLLER_3WARE_9000_CHAR 0x05 // set by guess_device_type() -#define CONTROLLER_3WARE_678K_CHAR 0x06 // set by guess_device_type() -#define CONTROLLER_HPT 0x09 // SATA drives behind HighPoint Raid controllers -#define CONTROLLER_CCISS 0x10 // CCISS controller +#define CONTROLLER_3WARE_678K 0x03 // NOT set by guess_device_type() +#define CONTROLLER_3WARE_9000_CHAR 0x04 // set by guess_device_type() +#define CONTROLLER_3WARE_678K_CHAR 0x05 // set by guess_device_type() +#define CONTROLLER_HPT 0x06 // SATA drives behind HighPoint Raid controllers +#define CONTROLLER_CCISS 0x07 // CCISS controller +#define CONTROLLER_ATACAM 0x08 static __unused const char *filenameandversion="$Id$"; @@ -315,6 +316,7 @@ static int get_ata_channel_unit ( const char* name, int* unit, int* dev) { // osst, nosst and sg. static const char * fbsd_dev_prefix = _PATH_DEV; static const char * fbsd_dev_ata_disk_prefix = "ad"; +static const char * fbsd_dev_atacam_disk_prefix = "ada"; static const char * fbsd_dev_scsi_disk_plus = "da"; static const char * fbsd_dev_scsi_pass = "pass"; static const char * fbsd_dev_scsi_tape1 = "sa"; @@ -332,6 +334,7 @@ int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan, // No Autodetection if device type was specified by user if (*type){ if(!strcmp(type,"ata")) return CONTROLLER_ATA; + if(!strcmp(type,"atacam")) return CONTROLLER_ATACAM; if(!strcmp(type,"cciss")) return CONTROLLER_CCISS; if(!strcmp(type,"scsi") || !strcmp(type,"sat")) goto handlescsi; if(!strcmp(type,"3ware")){ @@ -354,6 +357,13 @@ int parse_ata_chan_dev(const char * dev_name, struct freebsd_dev_channel *chan, // else advance pointer to following characters dev_name += dev_prefix_len; } + + // form /dev/ada* or ada* + if (!strncmp(fbsd_dev_atacam_disk_prefix, dev_name, + strlen(fbsd_dev_atacam_disk_prefix))) { + return CONTROLLER_ATACAM; + } + // form /dev/ad* or ad* if (!strncmp(fbsd_dev_ata_disk_prefix, dev_name, strlen(fbsd_dev_ata_disk_prefix))) { @@ -488,6 +498,14 @@ bool freebsd_smart_device::open() return false; } } + if (parse_ok == CONTROLLER_ATACAM) { + if ((fdchan->camdev = ::cam_open_device(dev,O_RDWR)) == NULL) { + perror("cam_open_device"); + free(fdchan); + errno = ENOENT; + return false; + } + } if (parse_ok == CONTROLLER_3WARE_678K_CHAR) { char buf[512]; @@ -575,6 +593,9 @@ bool freebsd_smart_device::close() failed=::close(fdchan->atacommand); #endif + if (fdchan->camdev != NULL) + cam_close_device(fdchan->camdev); + // if close succeeded, then remove from device list // Eduard, should we also remove it from list if close() fails? I'm // not sure. Here I only remove it from list if close() worked. @@ -602,6 +623,10 @@ public: protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); + + #ifdef IOCATAREQUEST + virtual int do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request); + #endif }; freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) @@ -610,6 +635,72 @@ freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_ { } +int freebsd_ata_device::do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request) +{ + return ioctl(con->device, IOCATAREQUEST, request); +} + +#if __FreeBSD_version > 800100 +class freebsd_atacam_device : public freebsd_ata_device +{ +public: + freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type) + : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type) + {} + +protected: + virtual int do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request); +}; + +int freebsd_atacam_device::do_cmd(struct freebsd_dev_channel* con, struct ata_ioc_request* request) +{ + union ccb ccb; + int camflags; + + memset(&ccb, 0, sizeof(ccb)); + + if (request->count == 0) + camflags = CAM_DIR_NONE; + else if (request->flags == ATA_CMD_READ) + camflags = CAM_DIR_IN; + else + camflags = CAM_DIR_OUT; + + cam_fill_ataio(&ccb.ataio, + 0, + NULL, + camflags, + MSG_SIMPLE_Q_TAG, + (u_int8_t*)request->data, + request->count, + request->timeout); + + // ata_28bit_cmd + ccb.ataio.cmd.flags = 0; + ccb.ataio.cmd.command = request->u.ata.command; + ccb.ataio.cmd.features = request->u.ata.feature; + ccb.ataio.cmd.lba_low = request->u.ata.lba; + ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8; + ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16; + ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f); + ccb.ataio.cmd.sector_count = request->u.ata.count; + + ccb.ccb_h.flags |= CAM_DEV_QFRZDIS; + + if (cam_send_ccb(con->camdev, &ccb) < 0) { + err(1, "cam_send_ccb"); + return -1; + } + + if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) + return 0; + + cam_error_print(con->camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); + return -1; +} + +#endif + int freebsd_ata_device::ata_command_interface(smart_command_set command, int select, char * data) { int fd=get_fd(); @@ -754,7 +845,7 @@ int freebsd_ata_device::ata_command_interface(smart_command_set command, int sel unsigned char low,high; #ifdef IOCATAREQUEST - if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error) + if ((retval=do_cmd(con, &request)) || request.error) #else if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error) #endif @@ -790,7 +881,7 @@ int freebsd_ata_device::ata_command_interface(smart_command_set command, int sel } #ifdef IOCATAREQUEST - if ((retval=ioctl(con->device, IOCATAREQUEST, &request)) || request.error) + if ((retval=do_cmd(con, &request)) || request.error) #else if ((retval=ioctl(con->atacommand, IOCATA, &iocmd)) || request.error) #endif @@ -1583,6 +1674,8 @@ public: protected: virtual ata_device * get_ata_device(const char * name, const char * type); + virtual ata_device * get_atacam_device(const char * name, const char * type); + virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); @@ -1614,6 +1707,11 @@ ata_device * freebsd_smart_interface::get_ata_device(const char * name, const ch return new freebsd_ata_device(this, name, type); } +ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type) +{ + return new freebsd_atacam_device(this, name, type); +} + scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type) { return new freebsd_scsi_device(this, name, type); @@ -2176,6 +2274,8 @@ smart_device * freebsd_smart_interface::autodetect_smart_device(const char * nam switch (guess) { case CONTROLLER_ATA : return new freebsd_ata_device(this, name, ""); + case CONTROLLER_ATACAM : + return new freebsd_atacam_device(this, name, ""); case CONTROLLER_SCSI: // Try to detect possible USB->(S)ATA bridge if (get_usb_id(name, vendor_id, product_id, version)) { diff --git a/smartmontools/os_freebsd.h b/smartmontools/os_freebsd.h index 9a59afb71221debfd6e026458f93bb20a8d7af05..f3f17626ca2f1bc0935dc68dd63daa71b3fd1a17 100644 --- a/smartmontools/os_freebsd.h +++ b/smartmontools/os_freebsd.h @@ -92,6 +92,7 @@ struct freebsd_dev_channel { #endif char* devname; // the SCSI device name int unitnum; // the SCSI unit number + struct cam_device *camdev; }; #define FREEBSD_MAXDEV 64