diff --git a/sm5/os_freebsd.cpp b/sm5/os_freebsd.cpp
index e9a435991059f2670579d2a083af8958880623ef..20a485f2cd817392989c17557e0b33e8dcc213a2 100644
--- a/sm5/os_freebsd.cpp
+++ b/sm5/os_freebsd.cpp
@@ -22,6 +22,7 @@
 #include <err.h>
 #include <camlib.h>
 #include <cam/scsi/scsi_message.h>
+#include <cam/scsi/scsi_pass.h>
 #if defined(__DragonFly__)
 #include <sys/nata.h>
 #else
@@ -33,6 +34,7 @@
 #include <glob.h>
 #include <fcntl.h>
 #include <stddef.h>
+#include <paths.h>
 
 
 #include "config.h"
@@ -44,9 +46,9 @@
 #include "extern.h"
 #include "os_freebsd.h"
 
-static const char *filenameandversion="$Id: os_freebsd.cpp,v 1.70 2008/12/17 12:30:18 dlukes Exp $";
+static __unused const char *filenameandversion="$Id: os_freebsd.cpp,v 1.71 2008/12/19 13:36:17 dlukes Exp $";
 
-const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp,v 1.70 2008/12/17 12:30:18 dlukes Exp $" \
+const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp,v 1.71 2008/12/19 13:36:17 dlukes Exp $" \
 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 extern smartmonctrl * con;
@@ -1051,98 +1053,260 @@ int guess_device_type (const char* dev_name) {
 // global variable holding byte count of allocated memory
 extern long long bytes;
 
-// we are going to take advantage of the fact that FreeBSD's devfs will only
-// have device entries for devices that exist.  So if we get the equivilent of
-// ls /dev/ad?, we have all the ATA devices on the system
+// we are using CAM subsystem XPT enumerator to found all SCSI devices on system
+// despite of it's names
 //
 // If any errors occur, leave errno set as it was returned by the
 // system call, and return <0.
-
+//
 // Return values:
-// -1 out of memory
-// -2 to -5 errors in glob
+// -1:   error
+// >=0: number of discovered devices
 
-int get_dev_names(char*** names, const char* prefix) {
+int get_dev_names_scsi(char*** names) {
   int n = 0;
-  char** mp;
-  int retglob,lim;
-  glob_t globbuf;
-  int i;
-  char pattern1[128],pattern2[128];
+  char** mp = NULL;
+  unsigned int i;
+  union ccb ccb;
+  int bufsize, fd = -1;
+  int skip_device = 0, skip_bus = 0, changed = 0;
+  char *devname = NULL;
+  int serrno=-1;
 
-  bzero(&globbuf,sizeof(globbuf));
   // in case of non-clean exit
   *names=NULL;
+  ccb.cdm.matches = NULL;
 
-  // handle 0-99 possible devices, will still be limited by MAX_NUM_DEV
-  sprintf(pattern1,"/dev/%s[0-9]",prefix);
-  sprintf(pattern2,"/dev/%s[0-9][0-9]",prefix);
-  
-  // Use glob to look for any directory entries matching the patterns
-  // first call inits with first pattern match, second call appends
-  // to first list. GLOB_NOCHECK results in no error if no more matches 
-  // found, however it does append the actual pattern to the list of 
-  // paths....
-  if ((retglob=glob(pattern1, GLOB_ERR|GLOB_NOCHECK, NULL, &globbuf)) ||
-      (retglob=glob(pattern2, GLOB_ERR|GLOB_APPEND|GLOB_NOCHECK,NULL,&globbuf))) {
-     int retval = -1;
-    // glob failed
-    if (retglob==GLOB_NOSPACE)
-      pout("glob(3) ran out of memory matching patterns (%s),(%s)\n",
-           pattern1, pattern2);
-    else if (retglob==GLOB_ABORTED)
-      pout("glob(3) aborted matching patterns (%s),(%s)\n",
-           pattern1, pattern2);
-    else if (retglob==GLOB_NOMATCH) {
-      pout("glob(3) found no matches for patterns (%s),(%s)\n",
-           pattern1, pattern2);
-      retval = 0;
+  if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
+    if (errno == ENOENT) /* There are no CAM device on this computer */
+      return 0;
+    serrno = errno;
+    pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
+    n = -1;
+    goto end;
+  }
+
+  // allocate space for up to MAX_NUM_DEV number of ATA devices
+  mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
+  if (mp == NULL) {
+    serrno=errno;
+    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
+    n = -1;
+    goto end;
+  };
+
+  bzero(&ccb, sizeof(union ccb));
+
+  ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
+  ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
+  ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
+
+  ccb.ccb_h.func_code = XPT_DEV_MATCH;
+  bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV;
+  ccb.cdm.match_buf_len = bufsize;
+  ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
+  if (ccb.cdm.matches == NULL) {
+	serrno = errno;
+	pout("can't malloc memory for matches on line %d\n", __LINE__);
+	n = -1;
+	goto end;
+  }
+  ccb.cdm.num_matches = 0;
+
+  ccb.cdm.num_patterns = 0;
+  ccb.cdm.pattern_buf_len = 0;
+
+  /*
+   * We do the ioctl multiple times if necessary, in case there are
+   * more than MAX_NUM_DEV nodes in the EDT.
+   */
+  do {
+    if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
+      serrno = errno;
+      pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
+      n = -1;
+      break;
+    }
+
+    if ((ccb.ccb_h.status != CAM_REQ_CMP)
+     || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
+        && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
+      pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
+      serrno = ENXIO;
+      n = -1;
+      goto end;
     }
-    else if (retglob)
-      pout("Unexplained error in glob(3) of patterns (%s),(%s)\n",
-           pattern1, pattern2);
-    
-    //  Free memory and return
-    globfree(&globbuf);
 
-    return retval;
+    for (i = 0; i < ccb.cdm.num_matches && n < MAX_NUM_DEV; i++) {
+      struct bus_match_result *bus_result;
+      struct device_match_result *dev_result;
+      struct periph_match_result *periph_result;
+
+      if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
+        bus_result = &ccb.cdm.matches[i].result.bus_result;
+
+        if (strcmp(bus_result->dev_name,"ata") == 0 /* ATAPICAM devices will be probed as ATA devices, skip'em there */
+         || strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */
+          skip_bus = 1;
+        else
+          skip_bus = 0;
+        changed = 1;
+      } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
+        dev_result = &ccb.cdm.matches[i].result.device_result;
+
+        if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
+          skip_device = 1;
+        else
+          skip_device = 0;
+
+//        /* Shall we skip non T_DIRECT devices ? */
+//        if (dev_result->inq_data.device != T_DIRECT)
+//          skip_device = 1;
+        changed = 1;
+      } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && skip_device == 0) { 
+        /* One device may be populated as many peripherals (pass0 & da 0 fo rexample). 
+         * We are searching for latest name
+        */
+        periph_result =  &ccb.cdm.matches[i].result.periph_result;
+        free(devname);
+        asprintf(&devname, "%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
+        if (devname == NULL) {
+          serrno=errno;
+          pout("Out of memory constructing scan SCSI device list (on line %d)\n", __LINE__);
+          n = -1;
+          goto end;
+        };
+        changed = 0;
+      };
+      
+      if (changed == 1 && devname != NULL) {
+        mp[n] = devname;
+        devname = NULL;
+        bytes+=1+strlen(mp[n]);
+        n++;
+        changed = 0;
+      };
+    }
+
+  } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE) && n < MAX_NUM_DEV);
+
+  if (devname != NULL) {
+    mp[n] = devname;
+    devname = NULL;
+    bytes+=1+strlen(mp[n]);
+    n++;
+  };
+
+  mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
+  bytes += (n)*(sizeof(char*)); // and set allocated byte count
+
+end:
+  free(ccb.cdm.matches);
+  if (fd>-1)
+    close(fd);
+  if (n <= 0) {
+    free(mp);
+    mp = NULL;
   }
 
-  // did we find too many paths?
-  lim = globbuf.gl_pathc < MAX_NUM_DEV ? globbuf.gl_pathc : MAX_NUM_DEV;
-  if (lim < globbuf.gl_pathc)
-    pout("glob(3) found %d > MAX=%d devices matching patterns (%s),(%s): ignoring %d paths\n", 
-         globbuf.gl_pathc, MAX_NUM_DEV, pattern1,pattern2,
-         globbuf.gl_pathc-MAX_NUM_DEV);
+  *names=mp;
+
+  if (serrno>-1)
+    errno=serrno;
+  return(n);
+}
+
+#ifndef ATA_DEVICE
+#define ATA_DEVICE "/dev/ata"
+#endif
+
+// we are using ATA subsystem enumerator to found all ATA devices on system
+// despite of it's names
+//
+// If any errors occur, leave errno set as it was returned by the
+// system call, and return <0.
+
+// Return values:
+// -1:   error
+// >=0: number of discovered devices
+int get_dev_names_ata(char*** names) {
+  struct ata_ioc_devices devices;
+  int fd=-1,maxchannel,serrno=-1,n=0;
+  char **mp = NULL;
+
+  *names=NULL;
+
+  if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) {
+    if (errno == ENOENT) /* There are no ATA device on this computer */
+      return 0;
+    serrno = errno;
+    pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno));
+    n = -1;
+    goto end;
+  };
   
-  // allocate space for up to lim number of ATA devices
-  if (!(mp =  (char **)calloc(lim, sizeof(char*)))){
-    pout("Out of memory constructing scan device list\n");
-    return -1;
-  }
+  if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
+    serrno = errno;
+    pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
+    n = -1;
+    goto end;
+  };
 
-  // now step through the list returned by glob.  No link checking needed
-  // in FreeBSD
-  for (i=0; i<globbuf.gl_pathc; i++){
-    // because of the NO_CHECK in calls to glob,
-    // the pattern itself will be added to path list..
-    // so ignore any paths that have the ']' from pattern
-    if (strchr(globbuf.gl_pathv[i],']') == NULL)
-      mp[n++] = CustomStrDup(globbuf.gl_pathv[i], 1, __LINE__, filenameandversion);
-  }
+  // allocate space for up to MAX_NUM_DEV number of ATA devices
+  mp =  (char **)calloc(MAX_NUM_DEV, sizeof(char*));
+  if (mp == NULL) {
+    serrno=errno;
+    pout("Out of memory constructing scan device list (on line %d)\n", __LINE__);
+    n = -1;
+    goto end;
+  };
 
-  globfree(&globbuf);
-  mp = (char **)realloc(mp,n*(sizeof(char*))); // shrink to correct size
+  for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) {
+    int j;
+    
+    if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
+      if (errno == ENXIO)
+        continue; /* such channel not exist */
+      pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno));
+      n = -1;
+      goto end;
+    };
+    for (j=0;j<=1 && n<MAX_NUM_DEV;j++) {
+      if (devices.name[j][0] != '\0') {
+        asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]);
+        if (mp[n] == NULL) {
+          pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
+          n = -1;
+          goto end;
+        };
+        bytes+=1+strlen(mp[n]);
+        n++;
+      };
+    };
+  };  
+  mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size
   bytes += (n)*(sizeof(char*)); // and set allocated byte count
+      
+end:
+  if (fd>=0)
+    close(fd);
+  if (n <= 0) {
+    free(mp);
+    mp = NULL;
+  }
+
   *names=mp;
+
+  if (serrno>-1)
+    errno=serrno;
   return n;
 }
 
 int make_device_names (char*** devlist, const char* name) {
   if (!strcmp(name,"SCSI"))
-    return get_dev_names(devlist,"da");
+    return get_dev_names_scsi(devlist);
   else if (!strcmp(name,"ATA"))
-    return get_dev_names(devlist,"ad");
+    return get_dev_names_ata(devlist);
   else
     return 0;
 }