vmware: support for listing pci device path

- Based on the disk controller, device/bus number creates a PCI device path
  and stores in volume details, return in volume response
- The location of the disk/device on virtual PCI bus inside the guest would be
  /dev/disk/by-path/<THIS_STRING>/ linked to virtual disk inside the guest
- Creates/sets PCI device path based on attach disk output

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 2471e08..d88feb2 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -183,6 +183,7 @@
     public static final String PASSWORD_ENABLED = "passwordenabled";
     public static final String SSHKEY_ENABLED = "sshkeyenabled";
     public static final String PATH = "path";
+    public static final String PCI_DEVICE_PATH = "pcidevicepath";
     public static final String POD_ID = "podid";
     public static final String POD_IDS = "podids";
     public static final String POLICY_ID = "policyid";
diff --git a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
index eeb4af9..e2dfe2a 100644
--- a/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/VolumeResponse.java
@@ -208,6 +208,10 @@
     @Param(description = "true if the volume is extractable, false otherwise")
     private Boolean extractable;
 
+    @SerializedName(ApiConstants.PCI_DEVICE_PATH)
+    @Param(description="Location of the device/disk on virtual PCI bus inside the guest. /dev/disk/by-path/<THIS_STRING>/ would be linked to virtual disk inside the guest.")
+    private String pciDevicePath;
+
     @SerializedName(ApiConstants.STATUS)
     @Param(description = "the status of the volume")
     private String status;
@@ -425,6 +429,10 @@
         this.extractable = extractable;
     }
 
+    public void setPciDevicePath(String pciDevicePath) {
+        this.pciDevicePath = pciDevicePath;
+    }
+
     public void setState(String state) {
         this.state = state;
     }
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
index bc454e7..5c5f842 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -31,6 +31,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.cloudstack.api.ApiConstants;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 
@@ -1345,6 +1346,7 @@
             AttachAnswer answer = new AttachAnswer(disk);
 
             if (isAttach) {
+                Map<String, String> diskDetails = new HashMap<String, String>();
                 String dataDiskController = controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER);
                 String rootDiskController = controllerInfo.get(VmDetailConstants.ROOK_DISK_CONTROLLER);
                 DiskControllerType rootDiskControllerType = DiskControllerType.getType(rootDiskController);
@@ -1362,7 +1364,9 @@
                 } else if (DiskControllerType.getType(dataDiskController) == DiskControllerType.osdefault) {
                     dataDiskController = vmMo.getRecommendedDiskController(null);
                 }
-                vmMo.attachDisk(new String[] {datastoreVolumePath}, morDs, dataDiskController);
+                String pciDevicePath = vmMo.attachDisk(new String[] {datastoreVolumePath}, morDs, dataDiskController);
+                diskDetails.put(ApiConstants.PCI_DEVICE_PATH, pciDevicePath);
+                answer.setDiskDetails(diskDetails);
             } else {
                 vmMo.removeAllSnapshots();
                 vmMo.detachDisk(datastoreVolumePath, false);
diff --git a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
index 68a578f..d501175 100644
--- a/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/VolumeJoinDaoImpl.java
@@ -22,6 +22,9 @@
 import javax.ejb.Local;
 import javax.inject.Inject;
 
+import com.cloud.storage.VolumeDetailVO;
+import com.cloud.storage.dao.VolumeDetailsDao;
+import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -50,6 +53,8 @@
     @Inject
     private ConfigurationDao  _configDao;
     @Inject
+    private VolumeDetailsDao _volDetailsDao;
+    @Inject
     public AccountManager _accountMgr;
 
     private final SearchBuilder<VolumeJoinVO> volSearch;
@@ -221,6 +226,12 @@
             }
         }
 
+        // update pci devicepath information
+        VolumeDetailVO volDetailVo = _volDetailsDao.findDetail(volume.getId(), ApiConstants.PCI_DEVICE_PATH);
+        if (volDetailVo != null) {
+            volResponse.setPciDevicePath(volDetailVo.getValue());
+        }
+
         volResponse.setExtractable(isExtractable);
         volResponse.setDisplayVolume(volume.isDisplayVolume());
         volResponse.setChainInfo(volume.getChainInfo());
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
index d61cb2e..ccbf04a 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -34,6 +34,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 
+import com.cloud.hypervisor.vmware.util.VmwareVirtualPciConstants;
 import org.apache.log4j.Logger;
 
 import com.google.gson.Gson;
@@ -1134,7 +1135,7 @@
         }
     }
 
-    public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference morDs, String diskController) throws Exception {
+    public String attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference morDs, String diskController) throws Exception {
 
         if(s_logger.isTraceEnabled())
             s_logger.trace("vCenter API trace - attachDisk(). target MOR: " + _mor.getValue() + ", vmdkDatastorePath: "
@@ -1194,8 +1195,22 @@
             _context.waitForTaskProgressDone(morTask);
         }
 
-        if(s_logger.isTraceEnabled())
+        if(s_logger.isTraceEnabled()) {
             s_logger.trace("vCenter API trace - attachDisk() done(successfully)");
+        }
+
+        int busNumber = getControllerBusNumber(controllerKey);
+
+        String bus = VmwareVirtualPciConstants.PCI_BUS_LSILOGIC_CONTROLLER[busNumber];
+        String device = VmwareVirtualPciConstants.PCI_DEVICE_LSILOGIC_CONTROLLER[busNumber];
+        int virtualNodeUnitNumber = unitNumber;
+        String pciBusPath = VmwareVirtualPciConstants.PCI_BUS_DOMAIN + bus + VmwareVirtualPciConstants.PCI_BUS_PATH_SEPARATOR_DOMAIN_BUS
+                + device + VmwareVirtualPciConstants.PCI_BUS_PATH_SEPARATOR_DEVICE_FUNC + VmwareVirtualPciConstants.PCI_FUNC_LSILOGIC_CONTROLLER
+                + VmwareVirtualPciConstants.PCI_BUS_PATH_SEPARATOR_FUNC_UNIT
+                + VmwareVirtualPciConstants.PCI_DEVICE_UNIT_PREFIX + virtualNodeUnitNumber + VmwareVirtualPciConstants.PCI_DEVICE_UNIT_POSTFIX;
+
+        s_logger.debug("PCI bus path for this disk is : " + pciBusPath);
+        return pciBusPath;
     }
 
     private int getControllerBusNumber(int controllerKey) throws Exception {
diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareVirtualPciConstants.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareVirtualPciConstants.java
new file mode 100644
index 0000000..ac13e9b
--- /dev/null
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareVirtualPciConstants.java
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.hypervisor.vmware.util;
+
+public interface VmwareVirtualPciConstants {
+    static final String PCI_BUS_DOMAIN = "pci-0000";
+    static final String PCI_BUS_PATH_SEPARATOR_DOMAIN_BUS = ":";
+    static final String PCI_BUS_PATH_SEPARATOR_BUS_DEVICE = ":";
+    static final String PCI_BUS_PATH_SEPARATOR_DEVICE_FUNC = ".";
+    static final String PCI_BUS_PATH_SEPARATOR_FUNC_UNIT = "-";
+    static final String[] PCI_BUS_LSILOGIC_CONTROLLER = {"00", "02", "02", "02"};
+    static final String PCI_FUNC_LSILOGIC_CONTROLLER = "0";
+    static final String[] PCI_DEVICE_LSILOGIC_CONTROLLER = {"10", "00", "01", "02"};
+    static final String PCI_DEVICE_UNIT_PREFIX = "scsi-0:0:";
+    static final String PCI_DEVICE_UNIT_POSTFIX = ":0";
+}