diff --git a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c index a6578c5c7e1367..02a6fe206f3019 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsis.c +++ b/drivers/scsi/ibmvscsi/ibmvscsis.c @@ -57,7 +57,7 @@ #define IBMVSCSIS_VERSION "v0.1" #define IBMVSCSIS_NAMELEN 32 -#define INITIAL_SRP_LIMIT 16 +#define INITIAL_SRP_LIMIT 800 #define DEFAULT_MAX_SECTORS 256 #define MAX_H_COPY_RDMA (128*1024) @@ -65,8 +65,6 @@ /* * Hypervisor calls. */ -#define h_send_crq(ua, l, h) \ - plpar_hcall_norets(H_SEND_CRQ, ua, l, h) #define h_reg_crq(ua, tok, sz)\ plpar_hcall_norets(H_REG_CRQ, ua, tok, sz); @@ -85,7 +83,6 @@ static unsigned max_vdma_size = MAX_H_COPY_RDMA; static const char ibmvscsis_driver_name[] = "ibmvscsis"; -static const char ibmvscsis_workq_name[] = "ibmvscsis"; static char system_id[64] = ""; static char partition_name[97] = "UNKNOWN"; static unsigned int partition_number = -1; @@ -100,8 +97,7 @@ struct ibmvscsis_cmnd { struct se_cmd se_cmd; /* Sense buffer that will be mapped into outgoing status */ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER]; - /* Pointer to ibmvscsis nexus memory */ - struct ibmvscsis_nexus *ibmvscsis_nexus; + u32 lun; }; struct ibmvscsis_crq_msg { @@ -119,11 +115,20 @@ struct ibmvscsis_nexus { struct se_session *se_sess; }; +struct ibmvscsis_tport { + /* SCSI protocol the tport is providing */ + u8 tport_proto_id; + /* ASCII formatted WWPN for SRP Target port */ + char tport_name[IBMVSCSIS_NAMELEN]; + /* Returned by ibmvscsis_make_tport() */ + struct se_wwn tport_wwn; + int lun_count; +}; + struct ibmvscsis_tpg { /* ibmvscsis port target portal group tag for TCM */ u16 tport_tpgt; - /* Used for ibmvscsis device reference to tpg_nexus - */ + /* Used for ibmvscsis device reference to tpg_nexus */ int tpg_ibmvscsis_count; /* Pointer to the TCM ibmvscsis I_T Nexus for this TPG endpoint */ struct ibmvscsis_nexus *tpg_nexus; @@ -132,27 +137,10 @@ struct ibmvscsis_tpg { /* Returned by ibmvscsis_make_tpg() */ struct se_portal_group se_tpg; /* Pointer back to ibmvscsis*/ - struct ibmvscsis_adapter *ibmvscsis_adapter; -}; - -struct ibmvscsis_tport { - /* SCSI protocol the tport is providing */ - u8 tport_proto_id; - /* Binary World Wide unique Port Name for SRP Target port */ - u64 tport_wwpn; - /* ASCII formatted WWPN for SRP Target port */ - char tport_name[IBMVSCSIS_NAMELEN]; - /* Returned by ibmvscsis_make_tport() */ - struct se_wwn tport_wwn; -}; - -struct ibmvscsis_nacl { - /* Returned by ibmvscsis_make_nodeacl() */ - struct se_node_acl se_node_acl; - /* Binary World Wide unique Port Name for SRP Initiator port */ - u64 iport_wwpn; - /* ASCII formatted WWPN for Sas Initiator port */ - char iport_name[IBMVSCSIS_NAMELEN]; + struct ibmvscsis_adapter *adapter; + struct ibmvscsis_cmnd *cmd; + bool enabled; + bool releasing; }; struct ibmvscsis_adapter { @@ -171,16 +159,22 @@ struct ibmvscsis_adapter { //TODO: FIX LIBSRP TO WORK WITH TCM struct srp_target *target; - bool release; struct list_head list; struct ibmvscsis_tport *tport; }; +struct ibmvscsis_nacl { + /* Returned by ibmvscsis_make_nexus */ + struct se_node_acl se_node_acl; +}; + static inline long h_copy_rdma(s64 length, u64 sliobn, u64 slioba, u64 dliobn, u64 dlioba) { long rc = 0; + mb(); + rc = plpar_hcall_norets(H_COPY_RDMA, length, sliobn, slioba, dliobn, dlioba); return rc; @@ -198,6 +192,40 @@ static inline void h_free_crq(uint32_t unit_address) } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); } +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); + + /* + * Ensure the command buffer is flushed to memory before handing it + * over to the other side to prevent it from fetching any stale data. + */ + mb(); + rc = plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); + pr_debug("ibmvscsis: ibmvcsis_send_crq rc = 0x%lx\n", rc); + + return rc; +} + +static inline union viosrp_iu *vio_iu(struct iu_entry *iue) +{ + return (union viosrp_iu *)(iue->sbuf->buf); +} + +static u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun) +{ + u16 result = (0x8000 | + ((target & 0x003f) << 8) | + ((bus & 0x0007) << 5) | + (lun & 0x001f)); + return ((u64) result) << 48; +} + static int ibmvscsis_check_true(struct se_portal_group *se_tpg) { return 1; @@ -298,6 +326,51 @@ static struct configfs_attribute *ibmvscsis_wwn_attrs[] = { NULL, }; +static ssize_t ibmvscsis_tpg_enable_show(struct config_item *item, char *page) +{ + + struct se_portal_group *se_tpg = to_tpg(item); + struct ibmvscsis_tpg *tpg = container_of(se_tpg, + struct ibmvscsis_tpg, se_tpg); + + return snprintf(page, PAGE_SIZE, "%d\n", (tpg->enabled) ? 1: 0); +} + +static ssize_t ibmvscsis_tpg_enable_store(struct config_item *item, + const char *page, size_t count) +{ + + struct se_portal_group *se_tpg = to_tpg(item); + struct ibmvscsis_tpg *tpg = container_of(se_tpg, + struct ibmvscsis_tpg, se_tpg); + unsigned long tmp; + int ret; + + ret = kstrtoul(page, 0, &tmp); + if (ret < 0) { + pr_err("Unable to extract srpt_tpg_store_enable\n"); + return -EINVAL; + } + + if ((tmp != 0) && (tmp != 1)) { + pr_err("Illegal value for srpt_tpg_store_enable: %lu\n", tmp); + return -EINVAL; + } + if (tmp == 1) + tpg->enabled = true; + else + tpg->enabled = false; + + return count; +} + +CONFIGFS_ATTR(ibmvscsis_tpg_, enable); + +static struct configfs_attribute *ibmvscsis_tpg_attrs[] = { + &ibmvscsis_tpg_attr_enable, + NULL, +}; + static int ibmvscsis_write_pending(struct se_cmd *se_cmd); static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd); static int ibmvscsis_queue_status(struct se_cmd *se_cmd); @@ -311,23 +384,22 @@ static void ibmvscsis_aborted_task(struct se_cmd *se_cmd) return; } -static int ibmvscsis_make_nexus(struct ibmvscsis_tpg *tpg, +static struct se_portal_group *ibmvscsis_make_nexus(struct ibmvscsis_tpg *tpg, const char *name) { - struct se_portal_group *se_tpg; struct ibmvscsis_nexus *nexus; + struct se_node_acl *acl; pr_debug("ibmvscsis: make nexus"); if (tpg->tpg_nexus) { pr_debug("tpg->tpg_nexus already exists\n"); - return -EEXIST; + ERR_PTR(-EEXIST); } - se_tpg = &tpg->se_tpg; nexus = kzalloc(sizeof(struct ibmvscsis_nexus), GFP_KERNEL); if (!nexus) { pr_err("Unable to allocate struct ibmvscsis_nexus\n"); - return -ENOMEM; + ERR_PTR(-ENOMEM); } /* * Initialize the struct se_session pointer and setup tagpool @@ -337,32 +409,34 @@ static int ibmvscsis_make_nexus(struct ibmvscsis_tpg *tpg, if (IS_ERR(nexus->se_sess)) { goto transport_init_fail; } + pr_debug("ibmvscsis: make_nexus: se_sess:%p\n", nexus->se_sess); /* * Since we are running in 'demo mode' this call will generate a * struct se_node_acl for the ibmvscsis struct se_portal_group with * the SCSI Initiator port name of the passed configfs group 'name'. */ - nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( - se_tpg, (unsigned char *)name); - if (!nexus->se_sess->se_node_acl) { + acl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, (unsigned char *)name); + if (!acl) { pr_debug("core_tpg_check_initiator_node_acl() failed" " for %s\n", name); goto acl_failed; } + nexus->se_sess->se_node_acl = acl; + /* * Now register the TCM ibmvscsis virtual I_T Nexus as active. */ - transport_register_session(se_tpg, nexus->se_sess->se_node_acl, + transport_register_session(&tpg->se_tpg, nexus->se_sess->se_node_acl, nexus->se_sess, nexus); tpg->tpg_nexus = nexus; - return 0; + return &tpg->se_tpg; acl_failed: transport_free_session(nexus->se_sess); transport_init_fail: kfree(nexus); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } static int ibmvscsis_drop_nexus(struct ibmvscsis_tpg *tpg) @@ -409,6 +483,7 @@ static void ibmvscsis_drop_tpg(struct se_portal_group *se_tpg) struct ibmvscsis_tpg *tpg = container_of(se_tpg, struct ibmvscsis_tpg, se_tpg); + tpg->releasing = true; //TODO: Add a release mechanism to remove vio /* * Release the virtual I_T Nexus for this ibmvscsis TPG @@ -429,10 +504,12 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, container_of(wwn, struct ibmvscsis_tport, tport_wwn); struct ibmvscsis_tpg *tpg; struct ibmvscsis_adapter *adapter; + struct se_portal_group *se_tpg; struct vio_dev *vdev; u16 tpgt; int ret; unsigned long flags; + pr_debug("ibmvscsis: maketpg\n"); if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); @@ -446,8 +523,10 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, if(ret == 0) { tpg = adapter->tpg; } - if(tpg) + if(tpg){ + tpg->adapter = adapter; goto found; + } } spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); return NULL; @@ -455,21 +534,25 @@ static struct se_portal_group *ibmvscsis_make_tpg(struct se_wwn *wwn, found: spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); tpg->tport = tport; + tport->tport_wwn = *wwn; tpg->tport_tpgt = tpgt; - pr_debug("ibmvscsis: make_tpg name:%s, tport_proto_id:%x\n", - name, tport->tport_proto_id); + pr_debug("ibmvscsis: make_tpg name:%s, tport_proto_id:%x, tpgt:%x\n", + &tport->tport_name[0], tport->tport_proto_id, tpgt); - ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); + ret = core_tpg_register(&tport->tport_wwn, &tpg->se_tpg, tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; } - if(ibmvscsis_make_nexus(tpg, name) < 0) { + se_tpg = ibmvscsis_make_nexus(tpg, &tport->tport_name[0]); + tpg->se_tpg = *se_tpg; + if(!&tpg->se_tpg) { pr_info("ibmvscsis: failed make nexus\n"); ibmvscsis_drop_tpg(&tpg->se_tpg); } + pr_debug("ibmvscsis: make_se_tpg: %p\n", &tpg->se_tpg); return &tpg->se_tpg; } @@ -503,21 +586,19 @@ static struct se_wwn *ibmvscsis_make_tport(struct target_fabric_configfs *tf, const char *name) { struct ibmvscsis_tport *tport; - u64 wwpn = 0; + int ret; tport = ibmvscsis_lookup_port(name); - pr_debug("make_tport(%s), pointer:%p\n", name, tport); + ret = -EINVAL; if(!tport) - return NULL; + goto err; - tport->tport_wwpn = wwpn; tport->tport_proto_id = SCSI_PROTOCOL_SRP; - - pr_debug("ibmvscsis: make_tport name:%s, %x\n", name, - tport->tport_proto_id); - - snprintf(&tport->tport_name[0], 256, "%s", name); + pr_debug("ibmvscsis: make_tport(%s), pointer:%p tport_id:%x\n", name, + tport, tport->tport_proto_id); return &tport->tport_wwn; +err: + return ERR_PTR(ret); } static void ibmvscsis_drop_tport(struct se_wwn *wwn) @@ -565,7 +646,6 @@ static struct attribute *ibmvscsis_dev_attrs[] = { &dev_attr_system_id.attr, &dev_attr_partition_number.attr, &dev_attr_unit_address.attr, - NULL }; ATTRIBUTE_GROUPS(ibmvscsis_dev); @@ -578,11 +658,6 @@ static struct class ibmvscsis_class = { .dev_groups = ibmvscsis_dev_groups, }; -static inline union viosrp_iu *vio_iu(struct iu_entry *iue) -{ - return (union viosrp_iu *)(iue->sbuf->buf); -} - static int send_iu(struct iu_entry *iue, u64 length, u8 format) { struct srp_target *target = iue->target; @@ -625,10 +700,9 @@ static int send_iu(struct iu_entry *iue, u64 length, u8 format) be64_to_cpu(crq_as_u64[0]), be64_to_cpu(crq_as_u64[1])); -// srp_iu_put(iue); + srp_iu_put(iue); - rc1 = h_send_crq(adapter->dma_dev->unit_address, - be64_to_cpu(crq_as_u64[0]), + rc1 = h_send_crq(adapter, be64_to_cpu(crq_as_u64[0]), be64_to_cpu(crq_as_u64[1])); if (rc1) { @@ -733,10 +807,12 @@ static int send_adapter_info(struct iu_entry *iue, strcpy(info->srp_version, "16.a"); strncpy(info->partition_name, partition_name, sizeof(info->partition_name)); - info->partition_number = partition_number; - info->mad_version = 1; - info->os_type = 2; - info->port_max_txu[0] = DEFAULT_MAX_SECTORS << 9; + pr_debug("ibmvscsis: partition_number: %x\n", partition_number); + + info->partition_number = cpu_to_be32(partition_number); + info->mad_version = cpu_to_be32(1); + info->os_type = cpu_to_be32(2); + info->port_max_txu[0] = cpu_to_be32(SCSI_MAX_SG_SEGMENTS * PAGE_SIZE); pr_debug("ibmvscsis: send info to remote: 0x%lx 0x%lx 0x%lx \ 0x%lx 0x%lx\n",(unsigned long)sizeof(*info), @@ -799,17 +875,34 @@ static void process_login(struct iu_entry *iue) { union viosrp_iu *iu = vio_iu(iue); struct srp_login_rsp *rsp = &iu->srp.login_rsp; - uint64_t tag = iu->srp.rsp.tag; + struct srp_login_rej *rej = &iu->srp.login_rej; + u64 tag = iu->srp.rsp.tag; + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + struct vio_dev *vdev = adapter->dma_dev; + char name[16]; /* * TODO handle case that requested size is wrong and buffer * format is wrong */ - memset(iu, 0, sizeof(struct srp_login_rsp)); + memset(iu, 0, max(sizeof(*rsp), sizeof(*rej))); + + snprintf(name, sizeof(name), "%x", vdev->unit_address); + +/* if(!adapter->tpg->enabled) { + rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); + pr_err("ibmvscsis: Rejected SRP_LOGIN_REQ because target %s" + " has not yet been enabled", name); + goto reject; + } +*/ rsp->opcode = SRP_LOGIN_RSP; rsp->req_lim_delta = cpu_to_be32(INITIAL_SRP_LIMIT); + pr_debug("ibmvscsis: process_login, tag:%llu\n", tag); + rsp->tag = tag; rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu)); rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu)); @@ -818,6 +911,16 @@ static void process_login(struct iu_entry *iue) | SRP_BUF_FORMAT_INDIRECT); send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT); + return; +/* +reject: + rej->opcode = SRP_LOGIN_REJ; + rej->tag = tag; + rej->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT + | SRP_BUF_FORMAT_INDIRECT); + + send_iu(iue, sizeof(*rej), VIOSRP_SRP_FORMAT); +*/ } static void process_tsk_mgmt(struct iu_entry *iue) @@ -844,130 +947,6 @@ static void process_tsk_mgmt(struct iu_entry *iue) VIOSRP_SRP_FORMAT); } -static int process_srp_iu(struct iu_entry *iue) -{ - union viosrp_iu *iu = vio_iu(iue); - struct srp_target *target = iue->target; - int done = 1; - u8 opcode = iu->srp.rsp.opcode; - unsigned long flags; - - switch (opcode) { - case SRP_LOGIN_REQ: - pr_debug("ibmvscsis: srploginreq"); - process_login(iue); - break; - case SRP_TSK_MGMT: - pr_debug("ibmvscsis: srp task mgmt"); - process_tsk_mgmt(iue); - break; - case SRP_CMD: - pr_debug("ibmvscsis:srpcmd"); - spin_lock_irqsave(&target->lock, flags); - list_add_tail(&iue->ilist, &target->cmd_queue); - spin_unlock_irqrestore(&target->lock, flags); - done = 0; - break; - case SRP_LOGIN_RSP: - case SRP_I_LOGOUT: - case SRP_T_LOGOUT: - case SRP_RSP: - case SRP_CRED_REQ: - case SRP_CRED_RSP: - case SRP_AER_REQ: - case SRP_AER_RSP: - pr_err("ibmvscsis: Unsupported type %u\n", opcode); - break; - default: - pr_err("ibmvscsis: Unknown type %u\n", opcode); - } - - return done; -} - -static void process_iu(struct viosrp_crq *crq, - struct ibmvscsis_adapter *adapter) -{ - struct iu_entry *iue; - long err; - - iue = srp_iu_get(adapter->target); - if (!iue) { - pr_err("Error getting IU from pool %p\n", iue); - return; - } - - iue->remote_token = crq->IU_data_ptr; - - err = h_copy_rdma(be16_to_cpu(crq->IU_length), adapter->riobn, - be64_to_cpu(crq->IU_data_ptr), - adapter->liobn, iue->sbuf->dma); - - if (err != H_SUCCESS) { - pr_err("ibmvscsis: %ld transferring data error %p\n", err, iue); - srp_iu_put(iue); - } - - if (crq->format == VIOSRP_MAD_FORMAT) { - process_mad_iu(iue); - } - else { - pr_debug("ibmvscsis: process srpiu"); - process_srp_iu(iue); - } -} - -static void process_crq(struct viosrp_crq *crq, - struct ibmvscsis_adapter *adapter) -{ - switch (crq->valid) { - case 0xC0: - /* initialization */ - switch (crq->format) { - case 0x01: - h_send_crq(adapter->dma_dev->unit_address, - 0xC002000000000000, 0); - break; - case 0x02: - break; - default: - pr_err("ibmvscsis: Unknown format %u\n", crq->format); - } - break; - case 0xFF: - /* transport event */ - break; - case 0x80: - /* real payload */ - switch (crq->format) { - case VIOSRP_SRP_FORMAT: - case VIOSRP_MAD_FORMAT: - pr_debug("ibmvscsis: case viosrp mad crq: 0x%x, 0x%x, \ - 0x%x, 0x%x, 0x%x, 0x%x, 0x%llx\n", - crq->valid, crq->format, crq->reserved, - crq->status, be16_to_cpu(crq->timeout), - be16_to_cpu(crq->IU_length), - be64_to_cpu(crq->IU_data_ptr)); - process_iu(crq, adapter); - break; - case VIOSRP_OS400_FORMAT: - case VIOSRP_AIX_FORMAT: - case VIOSRP_LINUX_FORMAT: - case VIOSRP_INLINE_FORMAT: - pr_err("ibmvscsis: Unsupported format %u\n", - crq->format); - break; - default: - pr_err("ibmvscsis: Unknown format %u\n", - crq->format); - } - break; - default: - pr_err("ibmvscsis: unknown message type 0x%02x!?\n", - crq->valid); - } -} - static inline struct viosrp_crq *next_crq(struct crq_queue *queue) { struct viosrp_crq *crq; @@ -978,12 +957,14 @@ static inline struct viosrp_crq *next_crq(struct crq_queue *queue) if (crq->valid & 0x80) { if (++queue->cur == queue->size) queue->cur = 0; + rmb(); } else crq = NULL; spin_unlock_irqrestore(&queue->lock, flags); return crq; } + /* * TODO: Needs to be rewritten to support TCM, use target_submit_cmd() * for dispatching incoming SCSI CDB's and payloads into target-core @@ -1077,15 +1058,6 @@ struct inquiry_data { char unique[158]; }; -//TODO: Need to rewrite make lun to support little endian -static u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun) -{ - u16 result = (0x8000 | - ((target & 0x003f) << 8) | - ((bus & 0x0007) << 5) | - (lun & 0x001f)); - return ((u64) result) << 48; -} //TODO: Needs to be rewritten to support TCM static int ibmvscsis_inquiry(struct ibmvscsis_adapter *adapter, struct srp_cmd *cmd, char *data) @@ -1344,9 +1316,9 @@ static int ibmvscsis_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, //TODO: Needs to be rewritten to support TCM static int ibmvscsis_cmnd_done(struct scsi_cmnd *sc) { - unsigned long flags; +// unsigned long flags; struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; - struct srp_target *target = iue->target; +/* struct srp_target *target = iue->target; int err = 0; if (scsi_sg_count(sc)) @@ -1364,7 +1336,7 @@ static int ibmvscsis_cmnd_done(struct scsi_cmnd *sc) } else send_rsp(iue, sc, NO_SENSE, 0x00); - /* done(sc); */ +*/ /* done(sc); */ srp_iu_put(iue); return 0; } @@ -1470,6 +1442,7 @@ static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, switch (cmd->cdb[0]) { case INQUIRY: + pr_debug("ibmvscsis: inquiry\n"); sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL); pg = alloc_page(GFP_KERNEL|__GFP_ZERO); sc->sdb.length = ibmvscsis_inquiry(adapter, cmd, @@ -1481,6 +1454,7 @@ static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, kfree(vsc); break; case REPORT_LUNS: + pr_debug("ibmvscsis: report_luns\n"); sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL); pg = alloc_page(GFP_KERNEL|__GFP_ZERO); sc->sdb.length = ibmvscsis_report_luns(adapter, cmd, @@ -1492,7 +1466,7 @@ static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, kfree(vsc); break; case MODE_SENSE: - + pr_debug("ibmvscsis: mode_sense\n"); sg_alloc_table(&sc->sdb.table, 1, GFP_KERNEL); pg = alloc_page(GFP_KERNEL|__GFP_ZERO); sc->sdb.length = ibmvscsis_mode_sense(adapter, @@ -1504,6 +1478,7 @@ static int ibmvscsis_queuecommand(struct ibmvscsis_adapter *adapter, kfree(vsc); break; default: + pr_debug("ibmvscsis: tcm_queuecommand\n"); tcm_queuecommand(adapter, vsc, cmd); break; } @@ -1538,36 +1513,11 @@ static void handle_cmd_queue(struct ibmvscsis_adapter *adapter) spin_unlock_irqrestore(&target->lock, flags); } -static void handle_crq(unsigned long data) -{ - struct ibmvscsis_adapter *adapter = - (struct ibmvscsis_adapter *) data; - struct viosrp_crq *crq; - int done = 0; - - while (!done) { - while ((crq = next_crq(&adapter->crq_queue)) != NULL) { - process_crq(crq, adapter); - crq->valid = 0x00; - } - - vio_enable_interrupts(adapter->dma_dev); - - crq = next_crq(&adapter->crq_queue); - if (crq) { - vio_disable_interrupts(adapter->dma_dev); - process_crq(crq, adapter); - crq->valid = 0x00; - } else - done = 1; - } -// handle_cmd_queue(adapter); -} - static irqreturn_t ibmvscsis_interrupt(int dummy, void *data) { struct ibmvscsis_adapter *adapter = data; + pr_debug("ibmvscsis: there is an interrupt\n"); vio_disable_interrupts(adapter->dma_dev); tasklet_schedule(&adapter->work_task); @@ -1599,11 +1549,233 @@ static int ibmvscsis_reset_crq_queue(struct ibmvscsis_adapter *adapter) return rc; } -static int crq_queue_create(struct crq_queue *queue, - struct ibmvscsis_adapter *adapter) + +static void crq_queue_destroy(struct ibmvscsis_adapter *adapter) { - int retrc; - int err; + struct vio_dev *vdev = adapter->dma_dev; + struct crq_queue *queue = &adapter->crq_queue; + + free_irq(vdev->irq, (void *)adapter); + tasklet_kill(&adapter->work_task); + h_free_crq(vdev->unit_address); + dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token, + queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); + + free_page((unsigned long)queue->msgs); +} + +/* Fill in the liobn and riobn fields on the adapter */ +static int read_dma_window(struct vio_dev *vdev, + struct ibmvscsis_adapter *adapter) +{ + const __be32 *dma_window; + const __be32 *prop; + + /* TODO Using of_parse_dma_window would be better, but it doesn't give + * a way to read multiple windows without already knowing the size of + * a window or the number of windows + */ + dma_window = + (const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window", + NULL); + if (!dma_window) { + pr_err("ibmvscsis: Couldn't find ibm,my-dma-window property\n"); + return -1; + } + + adapter->liobn = be32_to_cpu(*dma_window); + dma_window++; + + prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells", + NULL); + if (!prop) { + pr_warn("ibmvscsis: Couldn't find ibm, \ + #dma-address-cells property\n"); + dma_window++; + } else + dma_window += be32_to_cpu(*prop); + + prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells", + NULL); + if (!prop) { + pr_warn("ibmvscsis: Couldn't find ibm,#dma-size-cells property\n"); + dma_window++; + } else + dma_window += be32_to_cpu(*prop); + + /* dma_window should point to the second window now */ + adapter->riobn = be32_to_cpu(*dma_window); + + return 0; +} + +static int process_srp_iu(struct iu_entry *iue) +{ + union viosrp_iu *iu = vio_iu(iue); + struct srp_target *target = iue->target; + struct ibmvscsis_adapter *adapter = target->ldata; + u8 opcode = iu->srp.rsp.opcode; + unsigned long flags; + int err = 1; + + spin_lock_irqsave(&target->lock, flags); + if (adapter->tpg->releasing) { + spin_unlock_irqrestore(&target->lock, flags); + srp_iu_put(iue); + goto done; + } + spin_unlock_irqrestore(&target->lock, flags); + + switch (opcode) { + case SRP_LOGIN_REQ: + pr_debug("ibmvscsis: srploginreq"); + process_login(iue); + break; + case SRP_TSK_MGMT: + pr_debug("ibmvscsis: srp task mgmt"); + process_tsk_mgmt(iue); + break; + case SRP_CMD: + pr_debug("ibmvscsis: srpcmd"); + pr_debug("ibmvscsis: process_srp_iu, iu_entry: %llx\n", + (u64)iue->sbuf->buf); + err = ibmvscsis_queuecommand(adapter, iue); + if (err) { + pr_err("ibmvscsis: cannot queue iue %p %d\n", + iue, err); + srp_iu_put(iue); + } + break; + case SRP_LOGIN_RSP: + case SRP_I_LOGOUT: + case SRP_T_LOGOUT: + case SRP_RSP: + case SRP_CRED_REQ: + case SRP_CRED_RSP: + case SRP_AER_REQ: + case SRP_AER_RSP: + pr_err("ibmvscsis: Unsupported type %u\n", opcode); + break; + default: + pr_err("ibmvscsis: Unknown type %u\n", opcode); + } +done: + return err; +} + +static void process_iu(struct viosrp_crq *crq, + struct ibmvscsis_adapter *adapter) +{ + struct iu_entry *iue; + long err; + + iue = srp_iu_get(adapter->target); + if (!iue) { + pr_err("Error getting IU from pool %p\n", iue); + return; + } + + iue->remote_token = crq->IU_data_ptr; + + err = h_copy_rdma(be16_to_cpu(crq->IU_length), adapter->riobn, + be64_to_cpu(crq->IU_data_ptr), + adapter->liobn, iue->sbuf->dma); + + if (err != H_SUCCESS) { + pr_err("ibmvscsis: %ld transferring data error %p\n", err, iue); + srp_iu_put(iue); + } + + if (crq->format == VIOSRP_MAD_FORMAT) { + process_mad_iu(iue); + } + else { + pr_debug("ibmvscsis: process srpiu"); + process_srp_iu(iue); + } +} + +static void process_crq(struct viosrp_crq *crq, + struct ibmvscsis_adapter *adapter) +{ + switch (crq->valid) { + case 0xC0: + /* initialization */ + switch (crq->format) { + case 0x01: + h_send_crq(adapter, 0xC002000000000000, 0); + break; + case 0x02: + break; + default: + pr_err("ibmvscsis: Unknown format %u\n", crq->format); + } + break; + case 0xFF: + /* transport event */ + break; + case 0x80: + /* real payload */ + switch (crq->format) { + case VIOSRP_SRP_FORMAT: + case VIOSRP_MAD_FORMAT: + pr_debug("ibmvscsis: case viosrp mad crq: 0x%x, 0x%x, \ + 0x%x, 0x%x, 0x%x, 0x%x, 0x%llx\n", + crq->valid, crq->format, crq->reserved, + crq->status, be16_to_cpu(crq->timeout), + be16_to_cpu(crq->IU_length), + be64_to_cpu(crq->IU_data_ptr)); + process_iu(crq, adapter); + break; + case VIOSRP_OS400_FORMAT: + case VIOSRP_AIX_FORMAT: + case VIOSRP_LINUX_FORMAT: + case VIOSRP_INLINE_FORMAT: + pr_err("ibmvscsis: Unsupported format %u\n", + crq->format); + break; + default: + pr_err("ibmvscsis: Unknown format %u\n", + crq->format); + } + break; + default: + pr_err("ibmvscsis: unknown message type 0x%02x!?\n", + crq->valid); + } +} + +static void handle_crq(unsigned long data) +{ + struct ibmvscsis_adapter *adapter = + (struct ibmvscsis_adapter *) data; + struct viosrp_crq *crq; + int done = 0; + + while (!done) { + while ((crq = next_crq(&adapter->crq_queue)) != NULL) { + process_crq(crq, adapter); + crq->valid = 0x00; + } + + vio_enable_interrupts(adapter->dma_dev); + + crq = next_crq(&adapter->crq_queue); + if (crq) { + vio_disable_interrupts(adapter->dma_dev); + process_crq(crq, adapter); + crq->valid = 0x00; + } else + done = 1; + } +// handle_cmd_queue(adapter); +} + +static int crq_queue_create(struct crq_queue *queue, + struct ibmvscsis_adapter *adapter) +{ + int retrc; + int err; struct vio_dev *vdev = adapter->dma_dev; queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); @@ -1648,7 +1820,6 @@ static int crq_queue_create(struct crq_queue *queue, if (err) { pr_err("ibmvscsis: Error 0x%x h_send_crq\n", err); goto req_irq_failed; - } err = vio_enable_interrupts(vdev); @@ -1661,6 +1832,7 @@ static int crq_queue_create(struct crq_queue *queue, req_irq_failed: tasklet_kill(&adapter->work_task); + h_free_crq(vdev->unit_address); reg_crq_failed: dma_unmap_single(&vdev->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); @@ -1670,65 +1842,6 @@ static int crq_queue_create(struct crq_queue *queue, return -1; } -static void crq_queue_destroy(struct ibmvscsis_adapter *adapter) -{ - struct vio_dev *vdev = adapter->dma_dev; - struct crq_queue *queue = &adapter->crq_queue; - - free_irq(vdev->irq, (void *)adapter); - tasklet_kill(&adapter->work_task); - h_free_crq(vdev->unit_address); - dma_unmap_single(&adapter->dma_dev->dev, queue->msg_token, - queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); - - free_page((unsigned long)queue->msgs); -} - -/* Fill in the liobn and riobn fields on the adapter */ -static int read_dma_window(struct vio_dev *vdev, - struct ibmvscsis_adapter *adapter) -{ - const __be32 *dma_window; - const __be32 *prop; - - /* TODO Using of_parse_dma_window would be better, but it doesn't give - * a way to read multiple windows without already knowing the size of - * a window or the number of windows - */ - dma_window = - (const __be32 *)vio_get_attribute(vdev, "ibm,my-dma-window", - NULL); - if (!dma_window) { - pr_err("ibmvscsis: Couldn't find ibm,my-dma-window property\n"); - return -1; - } - - adapter->liobn = be32_to_cpu(*dma_window); - dma_window++; - - prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-address-cells", - NULL); - if (!prop) { - pr_warn("ibmvscsis: Couldn't find ibm, \ - #dma-address-cells property\n"); - dma_window++; - } else - dma_window += be32_to_cpu(*prop); - - prop = (const __be32 *)vio_get_attribute(vdev, "ibm,#dma-size-cells", - NULL); - if (!prop) { - pr_warn("ibmvscsis: Couldn't find ibm,#dma-size-cells property\n"); - dma_window++; - } else - dma_window += be32_to_cpu(*prop); - - /* dma_window should point to the second window now */ - adapter->riobn = be32_to_cpu(*dma_window); - - return 0; -} - /** * ibmvscsis_probe - ibm vscsis target initialize entry point * @param dev vio device struct @@ -1767,7 +1880,12 @@ static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id) adapter->target = target; adapter->tport = tport; adapter->tpg = tpg; - pr_debug("ibmvscsis: tport probe pointer:%p\n", tport); + + snprintf(&adapter->tport->tport_name[0], 256, "%s", dev_name(&vdev->dev)); + + pr_debug("ibmvscsis: probe- adapter: %p, target:%p, tpg:%p, tport:%p" + " tport_name:%s\n", + adapter, target, tpg, tport, tport->tport_name); ret = read_dma_window(adapter->dma_dev, adapter); if(ret != 0) { @@ -1780,7 +1898,6 @@ static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id) list_add_tail(&adapter->list, &ibmvscsis_dev_list); spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); - BUILD_BUG_ON_NOT_POWER_OF_2(INITIAL_SRP_LIMIT); ret = srp_target_alloc(adapter->target, &vdev->dev, INITIAL_SRP_LIMIT, SRP_MAX_IU_LEN); @@ -1794,7 +1911,7 @@ static int ibmvscsis_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto free_srp_target; } - ret = h_send_crq(adapter->dma_dev->unit_address, 0xC001000000000000LL, 0); + ret = h_send_crq(adapter, 0xC001000000000000LL, 0); if(ret) { pr_warn("ibmvscsis: Failed to send CRQ message\n"); goto destroy_crq_queue; @@ -1822,13 +1939,22 @@ static int ibmvscsis_remove(struct vio_dev *dev) { unsigned long flags; struct ibmvscsis_adapter *adapter = dev_get_drvdata(&dev->dev); + struct srp_target *target = adapter->target; + struct ibmvscsis_tpg *tpg = adapter->tpg; + struct ibmvscsis_tport *tport = adapter->tport; + + pr_debug("ibmvscsis:rem- adapter: %p, target:%p, tpg:%p, tport:%p\n", + adapter, target, tpg, tport); + srp_target_free(adapter->target); spin_lock_irqsave(&ibmvscsis_dev_lock, flags); list_del(&adapter->list); spin_unlock_irqrestore(&ibmvscsis_dev_lock, flags); crq_queue_destroy(adapter); - srp_target_free(adapter->target); + kfree(tpg); + kfree(tport); + kfree(target); kfree(adapter); return 0; @@ -1870,10 +1996,11 @@ static int get_system_info(void) num = of_get_property(rootdn, "ibm,partition-no", NULL); if (num) - partition_number = *num; + partition_number = of_read_number(num, 1); of_node_put(rootdn); + vdevdn = of_find_node_by_path("/vdevice"); vdevdn = of_find_node_by_path("/vdevice"); if (vdevdn) { const unsigned *mvds; @@ -1891,7 +2018,7 @@ static int get_system_info(void) static const struct target_core_fabric_ops ibmvscsis_ops = { .module = THIS_MODULE, .name = "ibmvscsis", - .max_data_sg_nents = 1024, + .max_data_sg_nents = SCSI_MAX_SG_SEGMENTS, .get_fabric_name = ibmvscsis_get_fabric_name, .tpg_get_wwn = ibmvscsis_get_fabric_wwn, .tpg_get_tag = ibmvscsis_get_tag, @@ -1923,6 +2050,7 @@ static const struct target_core_fabric_ops ibmvscsis_ops = { .fabric_drop_tpg = ibmvscsis_drop_tpg, .tfc_wwn_attrs = ibmvscsis_wwn_attrs, + .tfc_tpg_base_attrs = ibmvscsis_tpg_attrs, }; /** @@ -1970,8 +2098,6 @@ static int __init ibmvscsis_init(void) return 0; -//unregister_vio: -// vio_unregister_driver(&ibmvscsis_driver); unregister_target: target_unregister_template(&ibmvscsis_ops); unregister_class: