+config SCSI_IBMVSCSIS
+ tristate "IBM Virtual SCSI Server support"
+ depends on PPC_PSERIES && SCSI_SRP && TARGET_CORE
+ help
+ This is the IBM POWER Virtual SCSI Target Server
+
+ The userspace component needed to initialize the driver and
+ documentation can be found:
+
+ https://github.com/powervm/ibmvscsis
+
+ To compile this driver as a module, choose M here: the
+ module will be called ibmvstgt.
+
+#include <generated/utsrelease.h>
+#include "ibmvscsi.h"
+static inline long h_send_crq(struct ibmvscsis_adapter *adapter,
+ u64 word1, u64 word2)
+{
+ long rc;
+ struct vio_dev *vdev = adapter->dma_dev;
+
+ pr_debug("ibmvscsis: ibmvscsis_send_crq(0x%x, 0x%016llx, 0x%016llx)\n",
+ vdev->unit_address, word1, word2);
+
+static char system_id[64] = "";
+static char partition_name[97] = "UNKNOWN";
+static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item,
+ char *page)
+{
+ struct se_portal_group *se_tpg = to_tpg(item);
+ struct ibmvscsis_tport *tport = container_of(se_tpg,
+ struct ibmvscsis_tport, se_tpg);
+
+ return snprintf(page, PAGE_SIZE, "%d\n", (tport->enabled) ? 1 : 0);
+}
+static void ibmvscsis_modify_std_inquiry(struct se_cmd *se_cmd)
+{
+ struct se_device *dev = se_cmd->se_dev;
+ unsigned char *buf = NULL;
+ u32 cmd_len = se_cmd->data_length;
+
+ if (cmd_len <= INQ_DATA_OFFSET)
+ return;
+
+ buf = transport_kmap_data_sg(se_cmd);
+ if (buf) {
+ memcpy(&buf[8], "IBM ", 8);
+ if (dev->transport->get_device_type(dev) == TYPE_ROM)
+ memcpy(&buf[16], "VOPTA ", 16);
+ else
+ memcpy(&buf[16], "3303 NVDISK", 16);
+ memcpy(&buf[32], "0001", 4);
+ transport_kunmap_data_sg(se_cmd);
+ }
+}
+ default:
+ pr_err("ibmvscsis: unknown task mgmt func %d\n",
+ srp_tsk->tsk_mgmt_func);
+ cmd->se_cmd.se_tmr_req->response =
+ TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+ rc = -1;
+ break;
+ }
+
+ if (!rc) {
+static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter,
+ struct iu_entry *iue)
+{
+ struct srp_cmd *cmd = iue->sbuf->buf;
+ struct scsi_cmnd *sc;
+ struct ibmvscsis_cmnd *vsc;
+ int ret;
+
+ pr_debug("ibmvscsis: ibmvscsis_queuecommand\n");
+
+ vsc = kzalloc(sizeof(*vsc), GFP_KERNEL);
+static uint64_t ibmvscsis_unpack_lun(const uint8_t *lun, int len)
+{
+ uint64_t res = NO_SUCH_LUN;
+ int addressing_method;
+
+ if (unlikely(len < 2)) {
+ pr_err("Illegal LUN length %d, expected 2 bytes or more\n",
+ len);
+ goto out;
+ }
+
+ switch (len) {
+ case 8:
+ if ((*((__be64 *)lun) & cpu_to_be64(0x0000FFFFFFFFFFFFLL)) != 0)
+ goto out_err;
+ break;
+ case 4:
+ if (*((__be16 *)&lun[2]) != 0)
+ goto out_err;
+ break;
+ case 6:
+ if (*((__be32 *)&lun[2]) != 0)
+ goto out_err;
+ break;
+ case 2:
+ break;
+ default:
+ goto out_err;
+ }
+
+ addressing_method = (*lun) >> 6; /* highest two bits of byte 0 */
+ switch (addressing_method) {
+ case SCSI_LUN_ADDR_METHOD_PERIPHERAL:
+ case SCSI_LUN_ADDR_METHOD_FLAT:
+ case SCSI_LUN_ADDR_METHOD_LUN:
+ res = *(lun + 1) | (((*lun) & 0x3f) << 8);
+ break;
+
+ case SCSI_LUN_ADDR_METHOD_EXTENDED_LUN:
+ default:
+ pr_err("Unimplemented LUN addressing method %u\n",
+ addressing_method);
+ break;
+ }
+
+out:
+ return res;
+out_err:
+ pr_err("Support for multi-level LUNs has not yet been implemented\n");
+ goto out;
+}
+struct inquiry_data {
+ u8 qual_type;
+ u8 rmb_reserve;
+ u8 version;
+ u8 aerc_naca_hisup_format;
+ u8 addl_len;
+ u8 sccs_reserved;
+ u8 bque_encserv_vs_multip_mchngr_reserved;
+ u8 reladr_reserved_linked_cmdqueue_vs;
+ char vendor[8];
+ char product[16];
+ char revision[4];
+ char vendor_specific[20];
+ char reserved1[2];
+ char version_descriptor[16];
+ char reserved2[22];
+ char unique[158];
+};
+enum scsi_lun_addr_method {
+ SCSI_LUN_ADDR_METHOD_PERIPHERAL = 0,
+ SCSI_LUN_ADDR_METHOD_FLAT = 1,
+ SCSI_LUN_ADDR_METHOD_LUN = 2,
+ SCSI_LUN_ADDR_METHOD_EXTENDED_LUN = 3,
+};
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
new file mode 100644
index 0000000..0e32abd
--- /dev/null
+++ b/drivers/scsi/libsrp.c
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * SCSI RDMA Protocol lib functions