diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG
index 699f4fe73e716bb42ff2006d303412a84e5a51ff..07eb8f07c4b166115809f32408750fe603c30486 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>
 
+  [DL] FreeBSD: freebsd_ata_device::ata_pass_through implemented (part of ticket #18)
+
   [CF] drivedb.h updates:
        - Hitachi Travelstar 7K320 (ticket #28)
        - Hitachi Travelstar 7K500
diff --git a/smartmontools/os_freebsd.cpp b/smartmontools/os_freebsd.cpp
index b06ca5ed9359924e95c4121f2519e4f8515e1083..186787c5bf3a2622dc8ddcafef8c8e3e9a4ae6da 100644
--- a/smartmontools/os_freebsd.cpp
+++ b/smartmontools/os_freebsd.cpp
@@ -231,17 +231,17 @@ bool freebsd_smart_device::close()
 }
 
 /////////////////////////////////////////////////////////////////////////////
-/// Implement standard ATA support with old functions
+/// Implement standard ATA support
 
 class freebsd_ata_device
-: public /*implements*/ ata_device_with_command_set,
+: public /*implements*/ ata_device,
   public /*extends*/ freebsd_smart_device
 {
 public:
   freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
+  virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
 
 protected:
-  virtual int ata_command_interface(smart_command_set command, int select, char * data);
   virtual int do_cmd(struct ata_ioc_request* request);
 };
 
@@ -257,6 +257,111 @@ int freebsd_ata_device::do_cmd( struct ata_ioc_request* request)
   return ioctl(fd, IOCATAREQUEST, request);
 }
 
+
+
+bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
+{
+  if (!ata_cmd_is_ok(in, true, true, true)) // data_out_support
+    return false;
+
+  char buffer[512];
+  struct ata_ioc_request request;
+  bzero(&request,sizeof(struct ata_ioc_request));
+
+  request.timeout=SCSI_TIMEOUT_DEFAULT;
+  request.u.ata.command=in.in_regs.command;
+  request.u.ata.feature=in.in_regs.features;
+
+  request.u.ata.count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
+  request.u.ata.lba=
+      ((u_int64_t)in.in_regs.lba_high >> 8 & 0xFF) << 40 
+    | ((u_int64_t)in.in_regs.lba_mid >> 8 & 0xFF) << 32
+    | ((u_int64_t)in.in_regs.lba_low >> 8 & 0xFF) << 24
+    | ((u_int64_t)in.in_regs.lba_high & 0xFF) << 16
+    | ((u_int64_t)in.in_regs.lba_mid & 0xFF) << 8
+    | ((u_int64_t)in.in_regs.lba_low & 0xFF);
+
+  switch (in.direction) {
+    case ata_cmd_in::no_data:  
+      request.flags=ATA_CMD_CONTROL;
+      break;
+    case ata_cmd_in::data_in:  
+      request.flags=ATA_CMD_READ;
+      request.data=(char *)in.buffer;
+      request.count=in.size;
+      break;
+    case ata_cmd_in::data_out: 
+      request.flags=ATA_CMD_WRITE;
+      request.data=(char *)in.buffer;
+      request.count=in.size;
+      break;
+  }
+                          
+
+  // Command specific processing
+  if (in.in_regs.command == ATA_CHECK_POWER_MODE) {
+      request.data = buffer; 
+      request.data[0] = 0;
+      request.u.ata.feature=0;
+  }
+
+  clear_err(); 
+  errno = 0;
+  if (do_cmd(&request) || request.error)
+  {
+    if (!get_errno())
+      set_err(errno);
+    return false;
+  }
+
+  if (in.out_needed.error )
+    out.out_regs.error = request.error;
+  if (in.out_needed.sector_count )
+    out.out_regs.sector_count = request.u.ata.count;
+  if (in.out_needed.lba_high || in.out_needed.lba_high || in.out_needed.lba_high ) {
+    out.out_regs.lba_low = request.u.ata.lba & 0xFF | (request.u.ata.lba >> (24-8)) & 0xFF00;
+    out.out_regs.lba_mid = (request.u.ata.lba >> 8) & 0xFF | (request.u.ata.lba >> (32-8)) & 0xFF00;
+    out.out_regs.lba_high = (request.u.ata.lba >> 16) & 0xFF | (request.u.ata.lba >> (40-8)) & 0xFF00;
+  };
+
+
+  // Command specific processing
+  if (in.in_regs.command == ATA_SMART_CMD
+       && in.in_regs.features == ATA_SMART_STATUS
+       && in.out_needed.lba_high)
+  {
+    unsigned const char normal_lo=0x4f, normal_hi=0xc2;
+    unsigned const char failed_lo=0xf4, failed_hi=0x2c;
+
+#if (FREEBSDVER < 502000)
+    printwarning(NO_RETURN,NULL);
+#endif
+
+    // Cyl low and Cyl high unchanged means "Good SMART status"
+    if (!(out.out_regs.lba_mid==normal_lo && out.out_regs.lba_high==normal_hi)
+    // These values mean "Bad SMART status"
+        && !(out.out_regs.lba_mid==failed_lo && out.out_regs.lba_high==failed_hi))
+
+    {
+      // We haven't gotten output that makes sense; print out some debugging info
+      char buf[512];
+      sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
+        (int)request.u.ata.command,
+        (int)request.u.ata.feature,
+        (int)request.u.ata.count,
+        (int)((request.u.ata.lba) & 0xff),
+        (int)((request.u.ata.lba>>8) & 0xff),
+        (int)((request.u.ata.lba>>16) & 0xff),
+        (int)request.error);
+      printwarning(BAD_SMART,buf);
+      out.out_regs.lba_high = failed_hi; 
+      out.out_regs.lba_mid = failed_lo;
+    }
+  }
+
+  return true;
+}
+
 #if FREEBSDVER > 800100
 class freebsd_atacam_device : public freebsd_ata_device
 {
@@ -341,168 +446,6 @@ int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request)
 
 #endif
 
-int freebsd_ata_device::ata_command_interface(smart_command_set command, int select, char * data)
-{
- int retval, copydata=0;
- struct ata_ioc_request request;
- unsigned char buff[512];
-
- bzero(buff,512);
- bzero(&request,sizeof(struct ata_ioc_request));
- bzero(buff,512);
-
- request.u.ata.command=ATA_SMART_CMD;
- request.timeout=SCSI_TIMEOUT_DEFAULT;
- switch (command){
- case READ_VALUES:
-  request.u.ata.feature=ATA_SMART_READ_VALUES;
-  request.u.ata.lba=0xc24f<<8;
-  request.flags=ATA_CMD_READ;
-  request.data=(char *)buff;
-  request.count=512;
-  copydata=1;
-  break;
- case READ_THRESHOLDS:
-  request.u.ata.feature=ATA_SMART_READ_THRESHOLDS;
-  request.u.ata.count=1;
-  request.u.ata.lba=1|(0xc24f<<8);
-  request.flags=ATA_CMD_READ;
-  request.data=(char *)buff;
-  request.count=512;
-  copydata=1;
-  break;
- case READ_LOG:
-  request.u.ata.feature=ATA_SMART_READ_LOG_SECTOR;
-  request.u.ata.lba=select|(0xc24f<<8);
-  request.u.ata.count=1;
-  request.flags=ATA_CMD_READ;
-  request.data=(char *)buff;
-  request.count=512;
-  copydata=1;
-  break;
- case IDENTIFY:
-  request.u.ata.command=ATA_IDENTIFY_DEVICE;
-  request.flags=ATA_CMD_READ;
-  request.data=(char *)buff;
-  request.count=512;
-  copydata=1;
-  break;
- case PIDENTIFY:
-  request.u.ata.command=ATA_IDENTIFY_PACKET_DEVICE;
-  request.flags=ATA_CMD_READ;
-  request.data=(char *)buff;
-  request.count=512;
-  copydata=1;
-  break;
- case ENABLE:
-  request.u.ata.feature=ATA_SMART_ENABLE;
-  request.u.ata.lba=0xc24f<<8;
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case DISABLE:
-  request.u.ata.feature=ATA_SMART_DISABLE;
-  request.u.ata.lba=0xc24f<<8;
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case AUTO_OFFLINE:
-  // NOTE: According to ATAPI 4 and UP, this command is obsolete
-  request.u.ata.feature=ATA_SMART_AUTO_OFFLINE;
-  request.u.ata.lba=0xc24f<<8;                                                                                                                                         
-  request.u.ata.count=select;                                                                                                                                          
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case AUTOSAVE:
-  request.u.ata.feature=ATA_SMART_AUTOSAVE;
-  request.u.ata.lba=0xc24f<<8;
-  request.u.ata.count=select;
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case IMMEDIATE_OFFLINE:
-  request.u.ata.feature=ATA_SMART_IMMEDIATE_OFFLINE;
-  request.u.ata.lba = select|(0xc24f<<8); // put test in sector
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case STATUS_CHECK: // same command, no HDIO in FreeBSD
- case STATUS:
-  // this command only says if SMART is working.  It could be
-  // replaced with STATUS_CHECK below.
-  request.u.ata.feature=ATA_SMART_STATUS;
-  request.u.ata.lba=0xc24f<<8;
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case CHECK_POWER_MODE:
-  request.u.ata.command=ATA_CHECK_POWER_MODE;
-  request.u.ata.feature=0;
-  request.flags=ATA_CMD_CONTROL;
-  break;
- case WRITE_LOG:
-  memcpy(buff, data, 512);
-  request.u.ata.feature=ATA_SMART_WRITE_LOG_SECTOR;
-  request.u.ata.lba=select|(0xc24f<<8);
-  request.u.ata.count=1;
-  request.flags=ATA_CMD_WRITE;
-  request.data=(char *)buff;
-  request.count=512;
-  break;
- default:
-  pout("Unrecognized command %d in ata_command_interface()\n"
-   "Please contact " PACKAGE_BUGREPORT "\n", command);
-  errno=ENOSYS;
-  return -1;
- }
-
- if (command==STATUS_CHECK){
-  unsigned const char normal_lo=0x4f, normal_hi=0xc2;
-  unsigned const char failed_lo=0xf4, failed_hi=0x2c;
-  unsigned char low,high;
-
-  if ((retval=do_cmd(&request)) || request.error)
-  return -1;
-
-#if (FREEBSDVER < 502000)
-  printwarning(NO_RETURN,NULL);
-#endif
-
-  high = (request.u.ata.lba >> 16) & 0xff;
-  low = (request.u.ata.lba >> 8) & 0xff;
-
-  // Cyl low and Cyl high unchanged means "Good SMART status"
-  if (low==normal_lo && high==normal_hi)
-   return 0;
-
-  // These values mean "Bad SMART status"
-  if (low==failed_lo && high==failed_hi)
-   return 1;
-
-  // We haven't gotten output that makes sense; print out some debugging info
-  char buf[512];
-  sprintf(buf,"CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
-   (int)request.u.ata.command,
-   (int)request.u.ata.feature,
-   (int)request.u.ata.count,
-   (int)((request.u.ata.lba) & 0xff),
-   (int)((request.u.ata.lba>>8) & 0xff),
-   (int)((request.u.ata.lba>>16) & 0xff),
-   (int)request.error);
-  printwarning(BAD_SMART,buf);
-  return 0;   
- }
-
- if ((retval=do_cmd(&request)) || request.error)
- {
-  return -1;
- }
- // 
- if (command == CHECK_POWER_MODE) {
-  data[0] = request.u.ata.count & 0xff;
-  return 0;
- }
- if (copydata)
-  memcpy(data, buff, 512);
-
-  return 0;
-}
-
 /////////////////////////////////////////////////////////////////////////////
 /// Implement AMCC/3ware RAID support with old functions