diff --git a/ibmvstgt/src/ibmvstgt.c b/ibmvstgt/src/ibmvstgt.c index e3fe23c1b..b5c4a5078 100644 --- a/ibmvstgt/src/ibmvstgt.c +++ b/ibmvstgt/src/ibmvstgt.c @@ -57,16 +57,22 @@ #include "ibmvscsi.h" -#define INITIAL_SRP_LIMIT 16 -#define DEFAULT_MAX_SECTORS 256 +#define VSCSI_REQ_LIM 16 +#define MAD_REQ_LIM 1 +#define SRP_REQ_LIM (VSCSI_REQ_LIM - MAD_REQ_LIM) +/* Minimal trfr size that must be supported by a PAPR-compliant hypervisor. */ +#define MAX_H_COPY_RDMA (128*1024) #define TGT_NAME "ibmvstgt" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) +/* Force a compilation error if a constant expression is not a power of 2 */ +#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ + BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0)) +#endif /* * Hypervisor calls. */ -#define h_copy_rdma(l, sa, sb, da, db) \ - plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db) #define h_send_crq(ua, l, h) \ plpar_hcall_norets(H_SEND_CRQ, ua, l, h) #define h_reg_crq(ua, tok, sz)\ @@ -77,17 +83,25 @@ /* tmp - will replace with SCSI logging stuff */ #define eprintk(fmt, args...) \ do { \ - printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ + printk(KERN_ERR "%s(%d) " fmt, __func__, __LINE__, ##args); \ } while (0) /* #define dprintk eprintk */ #define dprintk(fmt, args...) +/* iu_entry.flags */ +enum iue_flags { + V_DIOVER, + V_WRITE, + V_LINKED, +}; + struct vio_port { struct vio_dev *dma_dev; struct crq_queue crq_queue; struct work_struct crq_work; + atomic_t req_lim_delta; unsigned long liobn; unsigned long riobn; struct srp_target *target; @@ -104,6 +118,8 @@ struct vio_port { static atomic_t ibmvstgt_device_count; static struct workqueue_struct *vtgtd; +static unsigned max_vdma_size = MAX_H_COPY_RDMA; +static struct scst_tgt_template ibmvstgt_template; #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) #define DEFAULT_IBMVSTGT_TRACE_FLAGS \ @@ -121,6 +137,29 @@ static char system_id[64] = ""; static char partition_name[97] = "UNKNOWN"; static unsigned int partition_number = -1; +static long h_copy_rdma(u64 length, unsigned long siobn, dma_addr_t saddr, + unsigned long diobn, dma_addr_t daddr) +{ + u64 bytes_copied = 0; + long rc; + + while (bytes_copied < length) { + u64 bytes_to_copy; + + bytes_to_copy = min_t(u64, length - bytes_copied, + max_vdma_size); + rc = plpar_hcall_norets(H_COPY_RDMA, bytes_to_copy, siobn, + saddr, diobn, daddr); + if (rc != H_SUCCESS) + return rc; + + bytes_copied += bytes_to_copy; + saddr += bytes_to_copy; + daddr += bytes_to_copy; + } + return H_SUCCESS; +} + static struct vio_port *target_to_port(struct srp_target *target) { return (struct vio_port *) target->ldata; @@ -160,6 +199,8 @@ static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format) else crq.cooked.status = 0x00; + srp_iu_put(iue); + rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]); if (rc1) { @@ -175,6 +216,8 @@ static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format) static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc, unsigned char status, unsigned char asc) { + struct srp_target *target = iue->target; + struct vio_port *vport = target_to_port(target); union viosrp_iu *iu = vio_iu(iue); uint64_t tag = iu->srp.rsp.tag; @@ -184,7 +227,8 @@ static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc, memset(iu, 0, sizeof(struct srp_rsp)); iu->srp.rsp.opcode = SRP_RSP; - iu->srp.rsp.req_lim_delta = 1; + iu->srp.rsp.req_lim_delta = __constant_cpu_to_be32(1 + + atomic_xchg(&vport->req_lim_delta, 0)); iu->srp.rsp.tag = tag; if (test_bit(V_DIOVER, &iue->flags)) @@ -205,15 +249,20 @@ static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc, int sense_data_len; sc_sense = scst_cmd_get_sense_buffer(sc); - sense_data_len = min(scst_cmd_get_sense_buffer_len(sc), - SRP_RSP_SENSE_DATA_LEN); - iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; - iu->srp.rsp.sense_data_len = sense_data_len; - memcpy(sense, sc_sense, sense_data_len); + if (SCST_SENSE_VALID(sc_sense)) { + sense_data_len + = min(scst_cmd_get_sense_buffer_len(sc), + SRP_RSP_SENSE_DATA_LEN); + iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; + iu->srp.rsp.sense_data_len + = cpu_to_be32(sense_data_len); + memcpy(sense, sc_sense, sense_data_len); + } } else { iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION; iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; - iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN; + iu->srp.rsp.sense_data_len + = __constant_cpu_to_be32(SRP_RSP_SENSE_DATA_LEN); /* Valid bit and 'current errors' */ sense[0] = (0x1 << 7 | 0x70); @@ -232,34 +281,6 @@ static int send_rsp(struct iu_entry *iue, struct scst_cmd *sc, return 0; } -static void handle_cmd_queue(struct srp_target *target) -{ - struct vio_port *vport = target_to_port(target); - struct scst_session *sess = vport->sess; - struct iu_entry *iue; - struct srp_cmd *cmd; - unsigned long flags; - int err; - -retry: - spin_lock_irqsave(&target->lock, flags); - - list_for_each_entry(iue, &target->cmd_queue, ilist) { - if (!test_and_set_bit(V_FLYING, &iue->flags)) { - spin_unlock_irqrestore(&target->lock, flags); - cmd = iue->sbuf->buf; - err = srp_cmd_queue(sess, cmd, iue); - if (err) { - eprintk("cannot queue cmd %p %d\n", cmd, err); - srp_iu_put(iue); - } - goto retry; - } - } - - spin_unlock_irqrestore(&target->lock, flags); -} - static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg, struct srp_direct_buf *md, int nmd, enum dma_data_direction dir, unsigned int rest) @@ -269,7 +290,6 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg, struct vio_port *vport = target_to_port(target); dma_addr_t token; long err; - unsigned int done = 0; int i, sidx, soff; sidx = soff = 0; @@ -278,22 +298,22 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg, for (i = 0; i < nmd && rest; i++) { unsigned int mdone, mlen; - mlen = min(rest, md[i].len); + mlen = min(rest, be32_to_cpu(md[i].len)); for (mdone = 0; mlen;) { int slen = min(sg_dma_len(sg + sidx) - soff, mlen); if (dir == DMA_TO_DEVICE) err = h_copy_rdma(slen, - vport->riobn, - md[i].va + mdone, - vport->liobn, - token + soff); + vport->riobn, + be64_to_cpu(md[i].va) + mdone, + vport->liobn, + token + soff); else err = h_copy_rdma(slen, - vport->liobn, - token + soff, - vport->riobn, - md[i].va + mdone); + vport->liobn, + token + soff, + vport->riobn, + be64_to_cpu(md[i].va) + mdone); if (err != H_SUCCESS) { eprintk("rdma error %d %d %ld\n", dir, slen, err); @@ -303,7 +323,6 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg, mlen -= slen; mdone += slen; soff += slen; - done += slen; if (soff == sg_dma_len(sg + sidx)) { sidx++; @@ -316,7 +335,7 @@ static int ibmvstgt_rdma(struct scst_cmd *sc, struct scatterlist *sg, int nsg, return -EIO; } } - }; + } rest -= mlen; } @@ -391,7 +410,8 @@ static int ibmvstgt_release(struct scst_tgt *scst_tgt) vport->releasing = true; spin_unlock_irqrestore(&target->lock, flags); - scst_unregister_session(sess, 0, NULL); + if (sess) + scst_unregister_session(sess, 0, NULL); return 0; } @@ -405,23 +425,34 @@ static int ibmvstgt_release(struct scst_tgt *scst_tgt) static int ibmvstgt_xmit_response(struct scst_cmd *sc) { struct iu_entry *iue = scst_cmd_get_tgt_priv(sc); + struct srp_target *target = iue->target; + struct vio_port *vport = target_to_port(target); + struct srp_cmd *srp_cmd; int ret; enum dma_data_direction dir; if (unlikely(scst_cmd_aborted(sc))) { scst_set_delivery_status(sc, SCST_CMD_DELIVERY_ABORTED); + atomic_inc(&vport->req_lim_delta); + srp_iu_put(iue); goto out; } - dir = srp_cmd_direction(&vio_iu(iue)->srp.cmd); + srp_cmd = &vio_iu(iue)->srp.cmd; + dir = srp_cmd_direction(srp_cmd); WARN_ON(dir != DMA_FROM_DEVICE && dir != DMA_TO_DEVICE); /* For read commands, transfer the data to the initiator. */ if (dir == DMA_FROM_DEVICE && scst_cmd_get_adjusted_resp_data_len(sc)) { - ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, - ibmvstgt_rdma, 1, 1); - if (ret) + ret = srp_transfer_data(sc, srp_cmd, ibmvstgt_rdma, true, true); + if (ret == -ENOMEM) + return SCST_TGT_RES_QUEUE_FULL; + else if (ret) { + PRINT_ERROR("%s: tag= %llu xmit_response failed", + __func__, (long long unsigned) + scst_cmd_get_tag(sc)); scst_set_delivery_status(sc, SCST_CMD_DELIVERY_FAILED); + } } send_rsp(iue, sc, scst_cmd_get_status(sc), 0); @@ -441,17 +472,20 @@ out: static int ibmvstgt_rdy_to_xfer(struct scst_cmd *sc) { struct iu_entry *iue = scst_cmd_get_tgt_priv(sc); - int ret = SCST_TGT_RES_SUCCESS; + struct srp_cmd *srp_cmd = &vio_iu(iue)->srp.cmd; + int ret; - WARN_ON(srp_cmd_direction(&vio_iu(iue)->srp.cmd) != DMA_TO_DEVICE); + WARN_ON(srp_cmd_direction(srp_cmd) != DMA_TO_DEVICE); /* Transfer the data from the initiator to the target. */ - ret = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); - if (ret == 0) { + ret = srp_transfer_data(sc, srp_cmd, ibmvstgt_rdma, true, true); + if (ret == 0) scst_rx_data(sc, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_SAME); - } else { + else if (ret == -ENOMEM) + return SCST_TGT_RES_QUEUE_FULL; + else { PRINT_ERROR("%s: tag= %llu xfer_data failed", __func__, - (long long unsigned)be64_to_cpu(scst_cmd_get_tag(sc))); + (long long unsigned)scst_cmd_get_tag(sc)); scst_rx_data(sc, SCST_RX_STATUS_ERROR, SCST_CONTEXT_SAME); } @@ -465,15 +499,6 @@ static int ibmvstgt_rdy_to_xfer(struct scst_cmd *sc) */ static void ibmvstgt_on_free_cmd(struct scst_cmd *sc) { - unsigned long flags; - struct iu_entry *iue = scst_cmd_get_tgt_priv(sc); - struct srp_target *target = iue->target; - - spin_lock_irqsave(&target->lock, flags); - list_del(&iue->ilist); - spin_unlock_irqrestore(&target->lock, flags); - - srp_iu_put(iue); } static int send_adapter_info(struct iu_entry *iue, @@ -508,7 +533,7 @@ static int send_adapter_info(struct iu_entry *iue, info->partition_number = partition_number; info->mad_version = 1; info->os_type = 2; - info->port_max_txu[0] = DEFAULT_MAX_SECTORS << 9; + info->port_max_txu[0] = ibmvstgt_template.sg_tablesize * PAGE_SIZE; /* Send our info to remote */ err = h_copy_rdma(sizeof(*info), vport->liobn, data_token, @@ -535,7 +560,9 @@ static void process_login(struct iu_entry *iue) struct vio_port *vport = target_to_port(target); char name[16]; - BUG_ON(vport->sess); + BUG_ON(!target); + BUG_ON(!target->tgt); + BUG_ON(!vport); memset(iu, 0, max(sizeof *rsp, sizeof *rej)); @@ -549,8 +576,14 @@ static void process_login(struct iu_entry *iue) goto reject; } - BUG_ON(!target); - sess = scst_register_session(target->tgt, 0, name, target, NULL, NULL); + if (vport->sess) { + PRINT_INFO("Closing session %s (%p) because a new login request" + " has been received", name, vport->sess); + scst_unregister_session(vport->sess, 0, NULL); + vport->sess = NULL; + } + + sess = scst_register_session(target->tgt, 0, name, vport, NULL, NULL); if (!sess) { rej->reason = __constant_cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); @@ -564,10 +597,15 @@ static void process_login(struct iu_entry *iue) * buffer format is wrong */ rsp->opcode = SRP_LOGIN_RSP; - rsp->req_lim_delta = INITIAL_SRP_LIMIT; + /* + * Avoid BUSY conditions by limiting the number of buffers used + * for the SRP protocol to the SCST SCSI command queue size. + */ + rsp->req_lim_delta = cpu_to_be32(min(SRP_REQ_LIM, + scst_get_max_lun_commands(NULL, 0))); rsp->tag = tag; - rsp->max_it_iu_len = sizeof(union srp_iu); - rsp->max_ti_iu_len = sizeof(union srp_iu); + rsp->max_it_iu_len = __constant_cpu_to_be32(sizeof(union srp_iu)); + rsp->max_ti_iu_len = __constant_cpu_to_be32(sizeof(union srp_iu)); /* direct and indirect */ rsp->buf_fmt = __constant_cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT); @@ -585,16 +623,6 @@ reject: send_iu(iue, sizeof *rsp, VIOSRP_SRP_FORMAT); } -static inline void queue_cmd(struct iu_entry *iue) -{ - struct srp_target *target = iue->target; - unsigned long flags; - - spin_lock_irqsave(&target->lock, flags); - list_add_tail(&iue->ilist, &target->cmd_queue); - spin_unlock_irqrestore(&target->lock, flags); -} - /** * struct mgmt_ctx - management command context information. * @iue: VIO SRP information unit associated with the management command. @@ -669,6 +697,7 @@ static int process_tsk_mgmt(struct iu_entry *iue) err: kfree(mgmt_ctx); + srp_iu_put(iue); return ret; } @@ -715,7 +744,7 @@ static void ibmvstgt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd) iu = vio_iu(iue); TRACE_DBG("%s: tag %lld status %d", - __func__, (long long unsigned)be64_to_cpu(iu->srp.rsp.tag), + __func__, (long long unsigned)iu->srp.rsp.tag, scst_mgmt_cmd_get_status(mcmnd)); send_rsp(iue, NULL, @@ -725,7 +754,7 @@ static void ibmvstgt_tsk_mgmt_done(struct scst_mgmt_cmd *mcmnd) kfree(mgmt_ctx); } -static int process_mad_iu(struct iu_entry *iue) +static void process_mad_iu(struct iu_entry *iue) { union viosrp_iu *iu = vio_iu(iue); struct viosrp_adapter_info *info; @@ -734,6 +763,7 @@ static int process_mad_iu(struct iu_entry *iue) switch (iu->mad.empty_iu.common.type) { case VIOSRP_EMPTY_IU_TYPE: eprintk("%s\n", "Unsupported EMPTY MAD IU"); + srp_iu_put(iue); break; case VIOSRP_ERROR_LOG_TYPE: eprintk("%s\n", "Unsupported ERROR LOG MAD IU"); @@ -753,24 +783,24 @@ static int process_mad_iu(struct iu_entry *iue) break; default: eprintk("Unknown type %u\n", iu->srp.rsp.opcode); + srp_iu_put(iue); } - - return 1; } -static int process_srp_iu(struct iu_entry *iue) +static void process_srp_iu(struct iu_entry *iue) { unsigned long flags; union viosrp_iu *iu = vio_iu(iue); struct srp_target *target = iue->target; struct vio_port *vport = target_to_port(target); - int done = 1; + int err; u8 opcode = iu->srp.rsp.opcode; spin_lock_irqsave(&target->lock, flags); if (vport->releasing) { spin_unlock_irqrestore(&target->lock, flags); - return done; + srp_iu_put(iue); + return; } spin_unlock_irqrestore(&target->lock, flags); @@ -779,11 +809,14 @@ static int process_srp_iu(struct iu_entry *iue) process_login(iue); break; case SRP_TSK_MGMT: - done = process_tsk_mgmt(iue) != SCST_MGMT_STATUS_SUCCESS; + process_tsk_mgmt(iue); break; case SRP_CMD: - queue_cmd(iue); - done = 0; + err = srp_cmd_queue(vport->sess, &iu->srp.cmd, iue); + if (err) { + eprintk("cannot queue cmd %p %d\n", &iu->srp.cmd, err); + srp_iu_put(iue); + } break; case SRP_LOGIN_RSP: case SRP_I_LOGOUT: @@ -794,12 +827,12 @@ static int process_srp_iu(struct iu_entry *iue) case SRP_AER_REQ: case SRP_AER_RSP: eprintk("Unsupported type %u\n", opcode); + srp_iu_put(iue); break; default: eprintk("Unknown type %u\n", opcode); + srp_iu_put(iue); } - - return done; } static void process_iu(struct viosrp_crq *crq, struct srp_target *target) @@ -807,7 +840,6 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target) struct vio_port *vport = target_to_port(target); struct iu_entry *iue; long err; - int done = 1; iue = srp_iu_get(target); if (!iue) { @@ -822,16 +854,13 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target) if (err != H_SUCCESS) { eprintk("%ld transferring data error %p\n", err, iue); - goto out; + srp_iu_put(iue); } if (crq->format == VIOSRP_MAD_FORMAT) - done = process_mad_iu(iue); + process_mad_iu(iue); else - done = process_srp_iu(iue); -out: - if (done) - srp_iu_put(iue); + process_srp_iu(iue); } #ifdef RHEL_MAJOR @@ -897,7 +926,7 @@ static int crq_queue_create(struct crq_queue *queue, struct srp_target *target) vio_enable_interrupts(vport->dma_dev); - h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0); + h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000ULL, 0); queue->cur = 0; spin_lock_init(&queue->lock); @@ -947,7 +976,7 @@ static void process_crq(struct viosrp_crq *crq, struct srp_target *target) switch (crq->format) { case 0x01: h_send_crq(vport->dma_dev->unit_address, - 0xC002000000000000, 0); + 0xC002000000000000ULL, 0); break; case 0x02: break; @@ -997,6 +1026,13 @@ static inline struct viosrp_crq *next_crq(struct crq_queue *queue) return crq; } +/** + * handle_crq() - Process the command/response queue. + * + * Note: Although this function is not thread-safe because of how it is + * scheduled it is guaranteed that this function is running on at most one CPU + * at any given time. + */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19) static void handle_crq(void *ctx) #else @@ -1028,8 +1064,97 @@ static void handle_crq(struct work_struct *work) } else done = 1; } +} - handle_cmd_queue(target); +static void ibmvstgt_get_product_id(const struct scst_tgt_dev *tgt_dev, + char *buf, const int size) +{ + WARN_ON(size != 16); + + /* + * AIX uses hardcoded device names. The AIX SCSI initiator even won't + * work unless we use the names VDASD and VOPTA. + */ + switch (tgt_dev->dev->type) { + case TYPE_DISK: + memcpy(buf, "VDASD blkdev ", 16); + break; + case TYPE_ROM: + memcpy(buf, "VOPTA blkdev ", 16); + break; + default: + snprintf(buf, size, "(devtype %d) ", tgt_dev->dev->type); + break; + } +} + +/* + * Extract target, bus and LUN information from a 64-bit LUN in CPU-order. + */ +#define GETTARGET(x) ((((uint16_t)(x) >> 8) & 0x003f)) +#define GETBUS(x) ((((uint16_t)(x) >> 5) & 0x0007)) +#define GETLUN(x) ((((uint16_t)(x) >> 0) & 0x001f)) + +static int ibmvstgt_get_serial(const struct scst_tgt_dev *tgt_dev, char *buf, + int size) +{ + struct scst_session *sess = tgt_dev->sess; + struct vio_port *vport = scst_sess_get_tgt_priv(sess); + uint64_t lun = tgt_dev->lun; + + return snprintf(buf, size, + "IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n", + system_id, partition_number, + vport->dma_dev->unit_address, + GETBUS(lun), GETTARGET(lun), GETLUN(lun)); +} + +/** + * ibmvstgt_get_transportid() - SCST TransportID callback function. + * + * See also SPC-3, section 7.5.4.5, TransportID for initiator ports using SRP. + */ +static int ibmvstgt_get_transportid(struct scst_session *sess, + uint8_t **transport_id) +{ + struct vio_port *vport; + struct spc_rdma_transport_id { + uint8_t protocol_identifier; + uint8_t reserved[7]; + union { + uint8_t id8[16]; + __be32 id32[4]; + } i_port_id; + }; + struct spc_rdma_transport_id *tr_id; + int res; + + if (!sess) { + res = SCSI_TRANSPORTID_PROTOCOLID_SRP; + goto out; + } + + vport = scst_sess_get_tgt_priv(sess); + BUG_ON(!vport); + + BUILD_BUG_ON(sizeof(*tr_id) != 24); + + res = -ENOMEM; + tr_id = kzalloc(sizeof(struct spc_rdma_transport_id), GFP_KERNEL); + if (!tr_id) { + PRINT_ERROR("%s", "Allocation of TransportID failed"); + goto out; + } + + res = 0; + tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP; + memset(&tr_id->i_port_id, 0, sizeof(tr_id->i_port_id)); + tr_id->i_port_id.id32[3] = cpu_to_be32(vport->dma_dev->unit_address); + + *transport_id = (uint8_t *)tr_id; + +out: + return res; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) @@ -1102,11 +1227,19 @@ static struct class ibmvstgt_class = { static struct scst_tgt_template ibmvstgt_template = { .name = TGT_NAME, + .preferred_addr_method = SCST_LUN_ADDR_METHOD_LUN, #ifdef RHEL_MAJOR .sg_tablesize = 1024, #else .sg_tablesize = SCSI_MAX_SG_SEGMENTS, #endif + .vendor = "IBM ", + .revision = "0001", + .fake_aca = true, + .get_product_id = ibmvstgt_get_product_id, + .get_serial = ibmvstgt_get_serial, + .get_vend_specific = ibmvstgt_get_serial, + #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = DEFAULT_IBMVSTGT_TRACE_FLAGS, .trace_flags = &trace_flag, @@ -1121,6 +1254,7 @@ static struct scst_tgt_template ibmvstgt_template = { .rdy_to_xfer = ibmvstgt_rdy_to_xfer, .on_free_cmd = ibmvstgt_on_free_cmd, .task_mgmt_fn_done = ibmvstgt_tsk_mgmt_done, + .get_initiator_port_transport_id = ibmvstgt_get_transportid, }; static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) @@ -1128,7 +1262,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) struct scst_tgt *scst_tgt; struct srp_target *target; struct vio_port *vport; - unsigned int *dma, dma_size; + const unsigned int *dma; + unsigned dma_size; int err = -ENOMEM; vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL); @@ -1148,13 +1283,13 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) vport->dma_dev = dev; target->ldata = vport; vport->target = target; - err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT, + BUILD_BUG_ON_NOT_POWER_OF_2(VSCSI_REQ_LIM); + err = srp_target_alloc(target, &dev->dev, VSCSI_REQ_LIM, SRP_MAX_IU_LEN); if (err) goto unregister_target; - dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window", - &dma_size); + dma = vio_get_attribute(dev, "ibm,my-dma-window", &dma_size); if (!dma || dma_size != 40) { eprintk("Couldn't get window property %d\n", dma_size); err = -EIO; @@ -1179,9 +1314,12 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) #else vport->dev.parent = &dev->dev; #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) snprintf(vport->dev.class_id, BUS_ID_SIZE, "ibmvstgt-%d", vport->dma_dev->unit_address); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) + snprintf(vport->dev.bus_id, BUS_ID_SIZE, "ibmvstgt-%d", + vport->dma_dev->unit_address); #else dev_set_name(&vport->dev, "ibmvstgt-%d", vport->dma_dev->unit_address); @@ -1212,11 +1350,21 @@ free_vport: static int ibmvstgt_remove(struct vio_dev *dev) { - struct srp_target *target = dev_get_drvdata(&dev->dev); - struct vio_port *vport = target->ldata; + struct srp_target *target; + struct vio_port *vport; + + target = dev_get_drvdata(&dev->dev); + if (!target) + return 0; atomic_dec(&ibmvstgt_device_count); + vport = target->ldata; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) + class_device_unregister(&vport->dev); +#else + device_unregister(&vport->dev); +#endif crq_queue_destroy(target); srp_target_free(target); scst_unregister_target(target->tgt); @@ -1225,6 +1373,65 @@ static int ibmvstgt_remove(struct vio_dev *dev) return 0; } +#ifdef CONFIG_SCST_PROC +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) +static int ibmvstgt_trace_level_show(struct seq_file *seq, void *v) +{ + return scst_proc_log_entry_read(seq, trace_flag, NULL); +} + +static ssize_t ibmvstgt_proc_trace_level_write(struct file *file, + const char __user *buf, size_t length, loff_t *off) +{ + return scst_proc_log_entry_write(file, buf, length, &trace_flag, + DEFAULT_IBMVSTGT_TRACE_FLAGS, NULL); +} + +static struct scst_proc_data ibmvstgt_log_proc_data = { + SCST_DEF_RW_SEQ_OP(ibmvstgt_proc_trace_level_write) + .show = ibmvstgt_trace_level_show, +}; +#endif + +static int ibmvstgt_register_procfs_entry(struct scst_tgt_template *tgt) +{ + int res = -ENOMEM; +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) + struct proc_dir_entry *p, *root; + + root = scst_proc_get_tgt_root(tgt); + if (!root) + goto out; + /* + * Fill in the scst_proc_data::data pointer, which is used in + * a printk(KERN_INFO ...) statement in + * scst_proc_log_entry_write() in scst_proc.c. + */ + ibmvstgt_log_proc_data.data = (char *)tgt->name; + p = scst_create_proc_entry(root, "trace_level", + &ibmvstgt_log_proc_data); + if (p) + res = 0; +#endif +out: + return res; +} + +static void ibmvstgt_unregister_procfs_entry(struct scst_tgt_template *tgt) +{ +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) + struct proc_dir_entry *root; + + root = scst_proc_get_tgt_root(tgt); + if (!root) + goto out; + remove_proc_entry("trace_level", root); +out: + ; +#endif +} +#endif /*CONFIG_SCST_PROC*/ + static struct vio_device_id ibmvstgt_device_table[] __devinitdata = { {"v-scsi-host", "IBM,v-scsi-host"}, {"",""} @@ -1244,7 +1451,7 @@ static struct vio_driver ibmvstgt_driver = { static int get_system_info(void) { - struct device_node *rootdn; + struct device_node *rootdn, *vdevdn; const char *id, *model, *name; const unsigned int *num; @@ -1266,6 +1473,18 @@ static int get_system_info(void) partition_number = *num; of_node_put(rootdn); + + vdevdn = of_find_node_by_path("/vdevice"); + if (vdevdn) { + const unsigned *mvds; + + mvds = of_get_property(vdevdn, "ibm,max-virtual-dma-size", + NULL); + if (mvds) + max_vdma_size = *mvds; + of_node_put(vdevdn); + } + return 0; } @@ -1281,7 +1500,11 @@ static int __init ibmvstgt_init(void) { int err = -ENOMEM; - printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n"); + printk(KERN_INFO "IBM eServer i/pSeries Virtual SCSI Target Driver\n"); + + err = get_system_info(); + if (err) + goto out; err = class_register(&ibmvstgt_class); if (err) @@ -1295,16 +1518,22 @@ static int __init ibmvstgt_init(void) if (!vtgtd) goto unregister_tgt; - err = get_system_info(); - if (err) - goto destroy_wq; - err = vio_register_driver(&ibmvstgt_driver); if (err) goto destroy_wq; +#ifdef CONFIG_SCST_PROC + err = ibmvstgt_register_procfs_entry(&ibmvstgt_template); + if (err) + goto unregister_driver; +#endif + return 0; +#ifdef CONFIG_SCST_PROC +unregister_driver: + vio_unregister_driver(&ibmvstgt_driver); +#endif destroy_wq: destroy_workqueue(vtgtd); unregister_tgt: @@ -1317,8 +1546,11 @@ out: static void __exit ibmvstgt_exit(void) { - printk("Unregister IBM virtual SCSI driver\n"); + printk(KERN_INFO "Unregister IBM virtual SCSI driver\n"); +#ifdef CONFIG_SCST_PROC + ibmvstgt_unregister_procfs_entry(&ibmvstgt_template); +#endif vio_unregister_driver(&ibmvstgt_driver); destroy_workqueue(vtgtd); scst_unregister_target_template(&ibmvstgt_template); diff --git a/ibmvstgt/src/libsrp.c b/ibmvstgt/src/libsrp.c index b41c6e847..eb99746ca 100644 --- a/ibmvstgt/src/libsrp.c +++ b/ibmvstgt/src/libsrp.c @@ -35,7 +35,7 @@ /* tmp - will replace with SCSI logging stuff */ #define eprintk(fmt, args...) \ do { \ - printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ + printk(KERN_ERR "%s(%d) " fmt, __func__, __LINE__, ##args); \ } while (0) /* #define dprintk eprintk */ #define dprintk(fmt, args...) @@ -139,10 +139,8 @@ int srp_target_alloc(struct srp_target *target, struct device *dev, int err; spin_lock_init(&target->lock); - INIT_LIST_HEAD(&target->cmd_queue); target->dev = dev; - dev_set_drvdata(target->dev, target); target->srp_iu_size = iu_size; target->rx_ring_size = nr; @@ -152,6 +150,7 @@ int srp_target_alloc(struct srp_target *target, struct device *dev, err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring); if (err) goto free_ring; + dev_set_drvdata(target->dev, target); return 0; @@ -163,6 +162,7 @@ EXPORT_SYMBOL_GPL(srp_target_alloc); void srp_target_free(struct srp_target *target) { + dev_set_drvdata(target->dev, NULL); srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size, target->srp_iu_size); srp_iu_pool_free(&target->iu_queue); @@ -185,7 +185,6 @@ struct iu_entry *srp_iu_get(struct srp_target *target) if (!iue) return iue; iue->target = target; - INIT_LIST_HEAD(&iue->ilist); iue->flags = 0; return iue; } @@ -204,39 +203,42 @@ EXPORT_SYMBOL_GPL(srp_iu_put); static int srp_direct_data(struct scst_cmd *sc, struct srp_direct_buf *md, enum dma_data_direction dir, srp_rdma_t rdma_io, - int dma_map, int ext_desc) + int dma_map) { struct iu_entry *iue = NULL; struct scatterlist *sg = NULL; int err, nsg = 0, len, sg_cnt; + u32 tsize; + enum dma_data_direction dma_dir; + + iue = scst_cmd_get_tgt_priv(sc); + if (dir == DMA_TO_DEVICE) { + scst_cmd_get_write_fields(sc, &sg, &sg_cnt); + tsize = scst_cmd_get_bufflen(sc); + dma_dir = DMA_FROM_DEVICE; + } else { + sg = scst_cmd_get_sg(sc); + sg_cnt = scst_cmd_get_sg_cnt(sc); + tsize = scst_cmd_get_adjusted_resp_data_len(sc); + dma_dir = DMA_TO_DEVICE; + } + + dprintk("%p %u %u %d\n", iue, tsize, be32_to_cpu(md->len), sg_cnt); + + len = min(tsize, be32_to_cpu(md->len)); if (dma_map) { - iue = scst_cmd_get_tgt_priv(sc); - if (dir == DMA_TO_DEVICE) { - scst_cmd_get_write_fields(sc, &sg, &sg_cnt); - } else { - sg = scst_cmd_get_sg(sc); - sg_cnt = scst_cmd_get_sg_cnt(sc); - } - - dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc), - md->len, sg_cnt); - - nsg = dma_map_sg(iue->target->dev, sg, sg_cnt, - DMA_BIDIRECTIONAL); + nsg = dma_map_sg(iue->target->dev, sg, sg_cnt, dma_dir); if (!nsg) { - printk(KERN_ERR "fail to map %p %d\n", iue, sg_cnt); - return 0; + eprintk(KERN_ERR "fail to map %p %d\n", iue, sg_cnt); + return -ENOMEM; } - len = min_t(unsigned, scst_cmd_get_expected_transfer_len(sc), - md->len); - } else - len = md->len; + } err = rdma_io(sc, sg, nsg, md, 1, dir, len); if (dma_map) - dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); + dma_unmap_sg(iue->target->dev, sg, nsg, dma_dir); return err; } @@ -251,23 +253,29 @@ static int srp_indirect_data(struct scst_cmd *sc, struct srp_cmd *cmd, struct scatterlist dummy, *sg = NULL; dma_addr_t token = 0; int err = 0; - int nmd, nsg = 0, len, sg_cnt; + int nmd, nsg = 0, len, sg_cnt = 0; + u32 tsize = 0; + enum dma_data_direction dma_dir; - if (dma_map || ext_desc) { - iue = scst_cmd_get_tgt_priv(sc); - if (dir == DMA_TO_DEVICE) { - scst_cmd_get_write_fields(sc, &sg, &sg_cnt); - } else { - sg = scst_cmd_get_sg(sc); - sg_cnt = scst_cmd_get_sg_cnt(sc); - } - - dprintk("%p %u %u %d %d\n", - iue, scsi_bufflen(sc), id->len, - cmd->data_in_desc_cnt, cmd->data_out_desc_cnt); + iue = scst_cmd_get_tgt_priv(sc); + if (dir == DMA_TO_DEVICE) { + scst_cmd_get_write_fields(sc, &sg, &sg_cnt); + tsize = scst_cmd_get_bufflen(sc); + dma_dir = DMA_FROM_DEVICE; + } else { + sg = scst_cmd_get_sg(sc); + sg_cnt = scst_cmd_get_sg_cnt(sc); + tsize = scst_cmd_get_adjusted_resp_data_len(sc); + dma_dir = DMA_TO_DEVICE; } - nmd = id->table_desc.len / sizeof(struct srp_direct_buf); + dprintk("%p %u %u %d %d\n", iue, tsize, be32_to_cpu(id->len), + be32_to_cpu(cmd->data_in_desc_cnt), + be32_to_cpu(cmd->data_out_desc_cnt)); + + len = min(tsize, be32_to_cpu(id->len)); + + nmd = be32_to_cpu(id->table_desc.len) / sizeof(struct srp_direct_buf); if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) || (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) { @@ -276,18 +284,19 @@ static int srp_indirect_data(struct scst_cmd *sc, struct srp_cmd *cmd, } if (ext_desc && dma_map) { - md = dma_alloc_coherent(iue->target->dev, id->table_desc.len, - &token, GFP_KERNEL); + md = dma_alloc_coherent(iue->target->dev, + be32_to_cpu(id->table_desc.len), + &token, GFP_KERNEL); if (!md) { eprintk("Can't get dma memory %u\n", id->table_desc.len); return -ENOMEM; } - sg_init_one(&dummy, md, id->table_desc.len); + sg_init_one(&dummy, md, be32_to_cpu(id->table_desc.len)); sg_dma_address(&dummy) = token; - sg_dma_len(&dummy) = id->table_desc.len; + sg_dma_len(&dummy) = be32_to_cpu(id->table_desc.len); err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE, - id->table_desc.len); + be32_to_cpu(id->table_desc.len)); if (err) { eprintk("Error copying indirect table %d\n", err); goto free_mem; @@ -299,26 +308,23 @@ static int srp_indirect_data(struct scst_cmd *sc, struct srp_cmd *cmd, rdma: if (dma_map) { - nsg = dma_map_sg(iue->target->dev, sg, sg_cnt, - DMA_BIDIRECTIONAL); + nsg = dma_map_sg(iue->target->dev, sg, sg_cnt, dma_dir); if (!nsg) { eprintk("fail to map %p %d\n", iue, sg_cnt); - err = -EIO; + err = -ENOMEM; goto free_mem; } - len = min_t(unsigned, scst_cmd_get_expected_transfer_len(sc), - id->len); - } else - len = id->len; + } err = rdma_io(sc, sg, nsg, md, nmd, dir, len); if (dma_map) - dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); + dma_unmap_sg(iue->target->dev, sg, nsg, dma_dir); free_mem: if (token && dma_map) - dma_free_coherent(iue->target->dev, id->table_desc.len, md, token); + dma_free_coherent(iue->target->dev, + be32_to_cpu(id->table_desc.len), md, token); return err; } @@ -345,10 +351,6 @@ static int data_out_desc_size(struct srp_cmd *cmd) return size; } -/* - * TODO: this can be called multiple times for a single command if it - * has very long data. - */ int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd, srp_rdma_t rdma_io, int dma_map, int ext_desc) { @@ -375,7 +377,7 @@ int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd, case SRP_DATA_DESC_DIRECT: md = (struct srp_direct_buf *) (cmd->add_data + offset); - err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc); + err = srp_direct_data(sc, md, dir, rdma_io, dma_map); break; case SRP_DATA_DESC_INDIRECT: id = (struct srp_indirect_buf *) @@ -392,7 +394,7 @@ int srp_transfer_data(struct scst_cmd *sc, struct srp_cmd *cmd, } EXPORT_SYMBOL_GPL(srp_transfer_data); -static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) +int srp_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) { struct srp_direct_buf *md; struct srp_indirect_buf *id; @@ -411,11 +413,11 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) break; case SRP_DATA_DESC_DIRECT: md = (struct srp_direct_buf *) (cmd->add_data + offset); - len = md->len; + len = be32_to_cpu(md->len); break; case SRP_DATA_DESC_INDIRECT: id = (struct srp_indirect_buf *) (cmd->add_data + offset); - len = id->len; + len = be32_to_cpu(id->len); break; default: eprintk("invalid data format %x\n", fmt); @@ -423,6 +425,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) } return len; } +EXPORT_SYMBOL_GPL(srp_data_length); int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info) { @@ -449,7 +452,7 @@ int srp_cmd_queue(struct scst_session *sess, struct srp_cmd *cmd, void *info) } dir = srp_cmd_direction(cmd); - len = vscsis_data_length(cmd, dir); + len = srp_data_length(cmd, dir); dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0], cmd->lun, dir, len, tag, (unsigned long long) cmd->tag); diff --git a/ibmvstgt/src/libsrpnew.h b/ibmvstgt/src/libsrpnew.h index b37cc0d5d..12ad31d62 100644 --- a/ibmvstgt/src/libsrpnew.h +++ b/ibmvstgt/src/libsrpnew.h @@ -10,13 +10,6 @@ #endif #include -enum iue_flags { - V_DIOVER, - V_WRITE, - V_LINKED, - V_FLYING, -}; - struct srp_buf { dma_addr_t dma; void *buf; @@ -38,7 +31,6 @@ struct srp_target { struct device *dev; spinlock_t lock; - struct list_head cmd_queue; size_t srp_iu_size; struct srp_queue iu_queue; @@ -51,7 +43,6 @@ struct srp_target { struct iu_entry { struct srp_target *target; - struct list_head ilist; dma_addr_t remote_token; unsigned long flags; @@ -67,6 +58,7 @@ extern void srp_target_free(struct srp_target *); extern struct iu_entry *srp_iu_get(struct srp_target *); extern void srp_iu_put(struct iu_entry *); +extern int srp_data_length(struct srp_cmd *, enum dma_data_direction); extern int srp_cmd_queue(struct scst_session *, struct srp_cmd *, void *); extern int srp_transfer_data(struct scst_cmd *, struct srp_cmd *, srp_rdma_t, int, int);