Loading Documentation/ABI/stable/sysfs-driver-ib_srp 0 → 100644 +156 −0 Original line number Diff line number Diff line What: /sys/class/infiniband_srp/srp-<hca>-<port_number>/add_target Date: January 2, 2006 KernelVersion: 2.6.15 Contact: linux-rdma@vger.kernel.org Description: Interface for making ib_srp connect to a new target. One can request ib_srp to connect to a new target by writing a comma-separated list of login parameters to this sysfs attribute. The supported parameters are: * id_ext, a 16-digit hexadecimal number specifying the eight byte identifier extension in the 16-byte SRP target port identifier. The target port identifier is sent by ib_srp to the target in the SRP_LOGIN_REQ request. * ioc_guid, a 16-digit hexadecimal number specifying the eight byte I/O controller GUID portion of the 16-byte target port identifier. * dgid, a 32-digit hexadecimal number specifying the destination GID. * pkey, a four-digit hexadecimal number specifying the InfiniBand partition key. * service_id, a 16-digit hexadecimal number specifying the InfiniBand service ID used to establish communication with the SRP target. How to find out the value of the service ID is specified in the documentation of the SRP target. * max_sect, a decimal number specifying the maximum number of 512-byte sectors to be transferred via a single SCSI command. * max_cmd_per_lun, a decimal number specifying the maximum number of outstanding commands for a single LUN. * io_class, a hexadecimal number specifying the SRP I/O class. Must be either 0xff00 (rev 10) or 0x0100 (rev 16a). The I/O class defines the format of the SRP initiator and target port identifiers. * initiator_ext, a 16-digit hexadecimal number specifying the identifier extension portion of the SRP initiator port identifier. This data is sent by the initiator to the target in the SRP_LOGIN_REQ request. * cmd_sg_entries, a number in the range 1..255 that specifies the maximum number of data buffer descriptors stored in the SRP_CMD information unit itself. With allow_ext_sg=0 the parameter cmd_sg_entries defines the maximum S/G list length for a single SRP_CMD, and commands whose S/G list length exceeds this limit after S/G list collapsing will fail. * allow_ext_sg, whether ib_srp is allowed to include a partial memory descriptor list in an SRP_CMD instead of the entire list. If a partial memory descriptor list has been included in an SRP_CMD the remaining memory descriptors are communicated from initiator to target via an additional RDMA transfer. Setting allow_ext_sg to 1 increases the maximum amount of data that can be transferred between initiator and target via a single SCSI command. Since not all SRP target implementations support partial memory descriptor lists the default value for this option is 0. * sg_tablesize, a number in the range 1..2048 specifying the maximum S/G list length the SCSI layer is allowed to pass to ib_srp. Specifying a value that exceeds cmd_sg_entries is only safe with partial memory descriptor list support enabled (allow_ext_sg=1). What: /sys/class/infiniband_srp/srp-<hca>-<port_number>/ibdev Date: January 2, 2006 KernelVersion: 2.6.15 Contact: linux-rdma@vger.kernel.org Description: HCA name (<hca>). What: /sys/class/infiniband_srp/srp-<hca>-<port_number>/port Date: January 2, 2006 KernelVersion: 2.6.15 Contact: linux-rdma@vger.kernel.org Description: HCA port number (<port_number>). What: /sys/class/scsi_host/host<n>/allow_ext_sg Date: May 19, 2011 KernelVersion: 2.6.39 Contact: linux-rdma@vger.kernel.org Description: Whether ib_srp is allowed to include a partial memory descriptor list in an SRP_CMD when communicating with an SRP target. What: /sys/class/scsi_host/host<n>/cmd_sg_entries Date: May 19, 2011 KernelVersion: 2.6.39 Contact: linux-rdma@vger.kernel.org Description: Maximum number of data buffer descriptors that may be sent to the target in a single SRP_CMD request. What: /sys/class/scsi_host/host<n>/dgid Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: InfiniBand destination GID used for communication with the SRP target. Differs from orig_dgid if port redirection has happened. What: /sys/class/scsi_host/host<n>/id_ext Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: Eight-byte identifier extension portion of the 16-byte target port identifier. What: /sys/class/scsi_host/host<n>/ioc_guid Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: Eight-byte I/O controller GUID portion of the 16-byte target port identifier. What: /sys/class/scsi_host/host<n>/local_ib_device Date: November 29, 2006 KernelVersion: 2.6.19 Contact: linux-rdma@vger.kernel.org Description: Name of the InfiniBand HCA used for communicating with the SRP target. What: /sys/class/scsi_host/host<n>/local_ib_port Date: November 29, 2006 KernelVersion: 2.6.19 Contact: linux-rdma@vger.kernel.org Description: Number of the HCA port used for communicating with the SRP target. What: /sys/class/scsi_host/host<n>/orig_dgid Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: InfiniBand destination GID specified in the parameters written to the add_target sysfs attribute. What: /sys/class/scsi_host/host<n>/pkey Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: A 16-bit number representing the InfiniBand partition key used for communication with the SRP target. What: /sys/class/scsi_host/host<n>/req_lim Date: October 20, 2010 KernelVersion: 2.6.36 Contact: linux-rdma@vger.kernel.org Description: Number of requests ib_srp can send to the target before it has to wait for more credits. For more information see also the SRP credit algorithm in the SRP specification. What: /sys/class/scsi_host/host<n>/service_id Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: InfiniBand service ID used for establishing communication with the SRP target. What: /sys/class/scsi_host/host<n>/zero_req_lim Date: September 20, 2006 KernelVersion: 2.6.18 Contact: linux-rdma@vger.kernel.org Description: Number of times the initiator had to wait before sending a request to the target because it ran out of credits. For more information see also the SRP credit algorithm in the SRP specification. Documentation/ABI/stable/sysfs-transport-srp 0 → 100644 +19 −0 Original line number Diff line number Diff line What: /sys/class/srp_remote_ports/port-<h>:<n>/delete Date: June 1, 2012 KernelVersion: 3.7 Contact: linux-scsi@vger.kernel.org, linux-rdma@vger.kernel.org Description: Instructs an SRP initiator to disconnect from a target and to remove all LUNs imported from that target. What: /sys/class/srp_remote_ports/port-<h>:<n>/port_id Date: June 27, 2007 KernelVersion: 2.6.24 Contact: linux-scsi@vger.kernel.org Description: 16-byte local SRP port identifier in hexadecimal format. An example: 4c:49:4e:55:58:20:56:49:4f:00:00:00:00:00:00:00. What: /sys/class/srp_remote_ports/port-<h>:<n>/roles Date: June 27, 2007 KernelVersion: 2.6.24 Contact: linux-scsi@vger.kernel.org Description: Role of the remote port. Either "SRP Initiator" or "SRP Target". drivers/infiniband/ulp/srp/ib_srp.c +185 −129 Original line number Diff line number Diff line Loading @@ -222,27 +222,29 @@ static int srp_new_cm_id(struct srp_target_port *target) static int srp_create_target_ib(struct srp_target_port *target) { struct ib_qp_init_attr *init_attr; struct ib_cq *recv_cq, *send_cq; struct ib_qp *qp; int ret; init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); if (!init_attr) return -ENOMEM; target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); if (IS_ERR(target->recv_cq)) { ret = PTR_ERR(target->recv_cq); if (IS_ERR(recv_cq)) { ret = PTR_ERR(recv_cq); goto err; } target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev, send_cq = ib_create_cq(target->srp_host->srp_dev->dev, srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); if (IS_ERR(target->send_cq)) { ret = PTR_ERR(target->send_cq); if (IS_ERR(send_cq)) { ret = PTR_ERR(send_cq); goto err_recv_cq; } ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP); ib_req_notify_cq(recv_cq, IB_CQ_NEXT_COMP); init_attr->event_handler = srp_qp_event; init_attr->cap.max_send_wr = SRP_SQ_SIZE; Loading @@ -251,30 +253,41 @@ static int srp_create_target_ib(struct srp_target_port *target) init_attr->cap.max_send_sge = 1; init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; init_attr->qp_type = IB_QPT_RC; init_attr->send_cq = target->send_cq; init_attr->recv_cq = target->recv_cq; init_attr->send_cq = send_cq; init_attr->recv_cq = recv_cq; target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); if (IS_ERR(target->qp)) { ret = PTR_ERR(target->qp); qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); if (IS_ERR(qp)) { ret = PTR_ERR(qp); goto err_send_cq; } ret = srp_init_qp(target, target->qp); ret = srp_init_qp(target, qp); if (ret) goto err_qp; if (target->qp) ib_destroy_qp(target->qp); if (target->recv_cq) ib_destroy_cq(target->recv_cq); if (target->send_cq) ib_destroy_cq(target->send_cq); target->qp = qp; target->recv_cq = recv_cq; target->send_cq = send_cq; kfree(init_attr); return 0; err_qp: ib_destroy_qp(target->qp); ib_destroy_qp(qp); err_send_cq: ib_destroy_cq(target->send_cq); ib_destroy_cq(send_cq); err_recv_cq: ib_destroy_cq(target->recv_cq); ib_destroy_cq(recv_cq); err: kfree(init_attr); Loading @@ -289,6 +302,9 @@ static void srp_free_target_ib(struct srp_target_port *target) ib_destroy_cq(target->send_cq); ib_destroy_cq(target->recv_cq); target->qp = NULL; target->send_cq = target->recv_cq = NULL; for (i = 0; i < SRP_RQ_SIZE; ++i) srp_free_iu(target->srp_host, target->rx_ring[i]); for (i = 0; i < SRP_SQ_SIZE; ++i) Loading Loading @@ -428,34 +444,50 @@ static int srp_send_req(struct srp_target_port *target) return status; } static void srp_disconnect_target(struct srp_target_port *target) static bool srp_queue_remove_work(struct srp_target_port *target) { /* XXX should send SRP_I_LOGOUT request */ bool changed = false; init_completion(&target->done); if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { shost_printk(KERN_DEBUG, target->scsi_host, PFX "Sending CM DREQ failed\n"); return; spin_lock_irq(&target->lock); if (target->state != SRP_TARGET_REMOVED) { target->state = SRP_TARGET_REMOVED; changed = true; } wait_for_completion(&target->done); spin_unlock_irq(&target->lock); if (changed) queue_work(system_long_wq, &target->remove_work); return changed; } static bool srp_change_state(struct srp_target_port *target, enum srp_target_state old, enum srp_target_state new) static bool srp_change_conn_state(struct srp_target_port *target, bool connected) { bool changed = false; spin_lock_irq(&target->lock); if (target->state == old) { target->state = new; if (target->connected != connected) { target->connected = connected; changed = true; } spin_unlock_irq(&target->lock); return changed; } static void srp_disconnect_target(struct srp_target_port *target) { if (srp_change_conn_state(target, false)) { /* XXX should send SRP_I_LOGOUT request */ if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { shost_printk(KERN_DEBUG, target->scsi_host, PFX "Sending CM DREQ failed\n"); } } } static void srp_free_req_data(struct srp_target_port *target) { struct ib_device *ibdev = target->srp_host->srp_dev->dev; Loading Loading @@ -489,32 +521,50 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost) device_remove_file(&shost->shost_dev, *attr); } static void srp_remove_work(struct work_struct *work) static void srp_remove_target(struct srp_target_port *target) { struct srp_target_port *target = container_of(work, struct srp_target_port, work); if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED)) return; spin_lock(&target->srp_host->target_lock); list_del(&target->list); spin_unlock(&target->srp_host->target_lock); WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); srp_del_scsi_host_attr(target->scsi_host); srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); srp_free_req_data(target); scsi_host_put(target->scsi_host); } static void srp_remove_work(struct work_struct *work) { struct srp_target_port *target = container_of(work, struct srp_target_port, remove_work); WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); spin_lock(&target->srp_host->target_lock); list_del(&target->list); spin_unlock(&target->srp_host->target_lock); srp_remove_target(target); } static void srp_rport_delete(struct srp_rport *rport) { struct srp_target_port *target = rport->lld_data; srp_queue_remove_work(target); } static int srp_connect_target(struct srp_target_port *target) { int retries = 3; int ret; WARN_ON_ONCE(target->connected); target->qp_in_error = false; ret = srp_lookup_path(target); if (ret) return ret; Loading @@ -534,6 +584,7 @@ static int srp_connect_target(struct srp_target_port *target) */ switch (target->status) { case 0: srp_change_conn_state(target, true); return 0; case SRP_PORT_REDIRECT: Loading Loading @@ -646,13 +697,14 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re static int srp_reconnect_target(struct srp_target_port *target) { struct ib_qp_attr qp_attr; struct ib_wc wc; struct Scsi_Host *shost = target->scsi_host; int i, ret; if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) if (target->state != SRP_TARGET_LIVE) return -EAGAIN; scsi_target_block(&shost->shost_gendev); srp_disconnect_target(target); /* * Now get a new local CM ID so that we avoid confusing the Loading @@ -660,21 +712,11 @@ static int srp_reconnect_target(struct srp_target_port *target) */ ret = srp_new_cm_id(target); if (ret) goto err; qp_attr.qp_state = IB_QPS_RESET; ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE); if (ret) goto err; goto unblock; ret = srp_init_qp(target, target->qp); ret = srp_create_target_ib(target); if (ret) goto err; while (ib_poll_cq(target->recv_cq, 1, &wc) > 0) ; /* nothing */ while (ib_poll_cq(target->send_cq, 1, &wc) > 0) ; /* nothing */ goto unblock; for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { struct srp_request *req = &target->req_ring[i]; Loading @@ -686,13 +728,16 @@ static int srp_reconnect_target(struct srp_target_port *target) for (i = 0; i < SRP_SQ_SIZE; ++i) list_add(&target->tx_ring[i]->list, &target->free_tx); target->qp_in_error = 0; ret = srp_connect_target(target); unblock: scsi_target_unblock(&shost->shost_gendev, ret == 0 ? SDEV_RUNNING : SDEV_TRANSPORT_OFFLINE); if (ret) goto err; if (!srp_change_state(target, SRP_TARGET_CONNECTING, SRP_TARGET_LIVE)) ret = -EAGAIN; shost_printk(KERN_INFO, target->scsi_host, PFX "reconnect succeeded\n"); return ret; Loading @@ -705,17 +750,8 @@ static int srp_reconnect_target(struct srp_target_port *target) * However, we have to defer the real removal because we * are in the context of the SCSI error handler now, which * will deadlock if we call scsi_remove_host(). * * Schedule our work inside the lock to avoid a race with * the flush_scheduled_work() in srp_remove_one(). */ spin_lock_irq(&target->lock); if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; INIT_WORK(&target->work, srp_remove_work); queue_work(ib_wq, &target->work); } spin_unlock_irq(&target->lock); srp_queue_remove_work(target); return ret; } Loading Loading @@ -1262,6 +1298,19 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) PFX "Recv failed with error code %d\n", res); } static void srp_handle_qp_err(enum ib_wc_status wc_status, enum ib_wc_opcode wc_opcode, struct srp_target_port *target) { if (target->connected && !target->qp_in_error) { shost_printk(KERN_ERR, target->scsi_host, PFX "failed %s status %d\n", wc_opcode & IB_WC_RECV ? "receive" : "send", wc_status); } target->qp_in_error = true; } static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) { struct srp_target_port *target = target_ptr; Loading @@ -1269,15 +1318,11 @@ static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { shost_printk(KERN_ERR, target->scsi_host, PFX "failed receive status %d\n", wc.status); target->qp_in_error = 1; break; } if (likely(wc.status == IB_WC_SUCCESS)) { srp_handle_recv(target, &wc); } else { srp_handle_qp_err(wc.status, wc.opcode, target); } } } Loading @@ -1288,16 +1333,12 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) struct srp_iu *iu; while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { shost_printk(KERN_ERR, target->scsi_host, PFX "failed send status %d\n", wc.status); target->qp_in_error = 1; break; } if (likely(wc.status == IB_WC_SUCCESS)) { iu = (struct srp_iu *) (uintptr_t) wc.wr_id; list_add(&iu->list, &target->free_tx); } else { srp_handle_qp_err(wc.status, wc.opcode, target); } } } Loading @@ -1311,16 +1352,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) unsigned long flags; int len; if (target->state == SRP_TARGET_CONNECTING) goto err; if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) { scmnd->result = DID_BAD_TARGET << 16; scmnd->scsi_done(scmnd); return 0; } spin_lock_irqsave(&target->lock, flags); iu = __srp_get_tx_iu(target, SRP_IU_CMD); if (!iu) Loading Loading @@ -1377,7 +1408,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) err_unlock: spin_unlock_irqrestore(&target->lock, flags); err: return SCSI_MLQUEUE_HOST_BUSY; } Loading Loading @@ -1419,6 +1449,33 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target) return -ENOMEM; } static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) { uint64_t T_tr_ns, max_compl_time_ms; uint32_t rq_tmo_jiffies; /* * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, * table 91), both the QP timeout and the retry count have to be set * for RC QP's during the RTR to RTS transition. */ WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); /* * Set target->rq_tmo_jiffies to one second more than the largest time * it can take before an error completion is generated. See also * C9-140..142 in the IBTA spec for more information about how to * convert the QP Local ACK Timeout value to nanoseconds. */ T_tr_ns = 4096 * (1ULL << qp_attr->timeout); max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; do_div(max_compl_time_ms, NSEC_PER_MSEC); rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); return rq_tmo_jiffies; } static void srp_cm_rep_handler(struct ib_cm_id *cm_id, struct srp_login_rsp *lrsp, struct srp_target_port *target) Loading Loading @@ -1478,6 +1535,8 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id, if (ret) goto error_free; target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); ret = ib_modify_qp(target->qp, qp_attr, attr_mask); if (ret) goto error_free; Loading Loading @@ -1599,6 +1658,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) case IB_CM_DREQ_RECEIVED: shost_printk(KERN_WARNING, target->scsi_host, PFX "DREQ received - connection closed\n"); srp_change_conn_state(target, false); if (ib_send_cm_drep(cm_id, NULL, 0)) shost_printk(KERN_ERR, target->scsi_host, PFX "Sending CM DREP failed\n"); Loading @@ -1608,7 +1668,6 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) shost_printk(KERN_ERR, target->scsi_host, PFX "connection closed\n"); comp = 1; target->status = 0; break; Loading Loading @@ -1636,10 +1695,6 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -1; init_completion(&target->tsk_mgmt_done); spin_lock_irq(&target->lock); Loading Loading @@ -1729,6 +1784,21 @@ static int srp_reset_host(struct scsi_cmnd *scmnd) return ret; } static int srp_slave_configure(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->host; struct srp_target_port *target = host_to_target(shost); struct request_queue *q = sdev->request_queue; unsigned long timeout; if (sdev->type == TYPE_DISK) { timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); blk_queue_rq_timeout(q, timeout); } return 0; } static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, char *buf) { Loading Loading @@ -1861,6 +1931,7 @@ static struct scsi_host_template srp_template = { .module = THIS_MODULE, .name = "InfiniBand SRP initiator", .proc_name = DRV_NAME, .slave_configure = srp_slave_configure, .info = srp_target_info, .queuecommand = srp_queuecommand, .eh_abort_handler = srp_abort, Loading Loading @@ -1894,11 +1965,14 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target) return PTR_ERR(rport); } rport->lld_data = target; spin_lock(&host->target_lock); list_add_tail(&target->list, &host->target_list); spin_unlock(&host->target_lock); target->state = SRP_TARGET_LIVE; target->connected = false; scsi_scan_target(&target->scsi_host->shost_gendev, 0, target->scsi_id, SCAN_WILD_CARD, 0); Loading Loading @@ -2188,6 +2262,7 @@ static ssize_t srp_create_target(struct device *dev, sizeof (struct srp_indirect_buf) + target->cmd_sg_cnt * sizeof (struct srp_direct_buf); INIT_WORK(&target->remove_work, srp_remove_work); spin_lock_init(&target->lock); INIT_LIST_HEAD(&target->free_tx); INIT_LIST_HEAD(&target->free_reqs); Loading Loading @@ -2232,7 +2307,6 @@ static ssize_t srp_create_target(struct device *dev, if (ret) goto err_free_ib; target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) { shost_printk(KERN_ERR, target->scsi_host, Loading Loading @@ -2422,8 +2496,7 @@ static void srp_remove_one(struct ib_device *device) { struct srp_device *srp_dev; struct srp_host *host, *tmp_host; LIST_HEAD(target_list); struct srp_target_port *target, *tmp_target; struct srp_target_port *target; srp_dev = ib_get_client_data(device, &srp_client); Loading @@ -2436,35 +2509,17 @@ static void srp_remove_one(struct ib_device *device) wait_for_completion(&host->released); /* * Mark all target ports as removed, so we stop queueing * commands and don't try to reconnect. * Remove all target ports. */ spin_lock(&host->target_lock); list_for_each_entry(target, &host->target_list, list) { spin_lock_irq(&target->lock); target->state = SRP_TARGET_REMOVED; spin_unlock_irq(&target->lock); } list_for_each_entry(target, &host->target_list, list) srp_queue_remove_work(target); spin_unlock(&host->target_lock); /* * Wait for any reconnection tasks that may have * started before we marked our target ports as * removed, and any target port removal tasks. * Wait for target port removal tasks. */ flush_workqueue(ib_wq); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { srp_del_scsi_host_attr(target->scsi_host); srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); srp_free_req_data(target); scsi_host_put(target->scsi_host); } flush_workqueue(system_long_wq); kfree(host); } Loading @@ -2478,6 +2533,7 @@ static void srp_remove_one(struct ib_device *device) } static struct srp_function_template ib_srp_transport_functions = { .rport_delete = srp_rport_delete, }; static int __init srp_init_module(void) Loading drivers/infiniband/ulp/srp/ib_srp.h +6 −5 Original line number Diff line number Diff line Loading @@ -80,9 +80,7 @@ enum { enum srp_target_state { SRP_TARGET_LIVE, SRP_TARGET_CONNECTING, SRP_TARGET_DEAD, SRP_TARGET_REMOVED SRP_TARGET_REMOVED, }; enum srp_iu_type { Loading Loading @@ -163,6 +161,9 @@ struct srp_target_port { struct ib_sa_query *path_query; int path_query_id; u32 rq_tmo_jiffies; bool connected; struct ib_cm_id *cm_id; int max_ti_iu_len; Loading @@ -173,12 +174,12 @@ struct srp_target_port { struct srp_iu *rx_ring[SRP_RQ_SIZE]; struct srp_request req_ring[SRP_CMD_SQ_SIZE]; struct work_struct work; struct work_struct remove_work; struct list_head list; struct completion done; int status; int qp_in_error; bool qp_in_error; struct completion tsk_mgmt_done; u8 tsk_mgmt_status; Loading drivers/scsi/scsi_transport_srp.c +27 −24 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
Documentation/ABI/stable/sysfs-driver-ib_srp 0 → 100644 +156 −0 Original line number Diff line number Diff line What: /sys/class/infiniband_srp/srp-<hca>-<port_number>/add_target Date: January 2, 2006 KernelVersion: 2.6.15 Contact: linux-rdma@vger.kernel.org Description: Interface for making ib_srp connect to a new target. One can request ib_srp to connect to a new target by writing a comma-separated list of login parameters to this sysfs attribute. The supported parameters are: * id_ext, a 16-digit hexadecimal number specifying the eight byte identifier extension in the 16-byte SRP target port identifier. The target port identifier is sent by ib_srp to the target in the SRP_LOGIN_REQ request. * ioc_guid, a 16-digit hexadecimal number specifying the eight byte I/O controller GUID portion of the 16-byte target port identifier. * dgid, a 32-digit hexadecimal number specifying the destination GID. * pkey, a four-digit hexadecimal number specifying the InfiniBand partition key. * service_id, a 16-digit hexadecimal number specifying the InfiniBand service ID used to establish communication with the SRP target. How to find out the value of the service ID is specified in the documentation of the SRP target. * max_sect, a decimal number specifying the maximum number of 512-byte sectors to be transferred via a single SCSI command. * max_cmd_per_lun, a decimal number specifying the maximum number of outstanding commands for a single LUN. * io_class, a hexadecimal number specifying the SRP I/O class. Must be either 0xff00 (rev 10) or 0x0100 (rev 16a). The I/O class defines the format of the SRP initiator and target port identifiers. * initiator_ext, a 16-digit hexadecimal number specifying the identifier extension portion of the SRP initiator port identifier. This data is sent by the initiator to the target in the SRP_LOGIN_REQ request. * cmd_sg_entries, a number in the range 1..255 that specifies the maximum number of data buffer descriptors stored in the SRP_CMD information unit itself. With allow_ext_sg=0 the parameter cmd_sg_entries defines the maximum S/G list length for a single SRP_CMD, and commands whose S/G list length exceeds this limit after S/G list collapsing will fail. * allow_ext_sg, whether ib_srp is allowed to include a partial memory descriptor list in an SRP_CMD instead of the entire list. If a partial memory descriptor list has been included in an SRP_CMD the remaining memory descriptors are communicated from initiator to target via an additional RDMA transfer. Setting allow_ext_sg to 1 increases the maximum amount of data that can be transferred between initiator and target via a single SCSI command. Since not all SRP target implementations support partial memory descriptor lists the default value for this option is 0. * sg_tablesize, a number in the range 1..2048 specifying the maximum S/G list length the SCSI layer is allowed to pass to ib_srp. Specifying a value that exceeds cmd_sg_entries is only safe with partial memory descriptor list support enabled (allow_ext_sg=1). What: /sys/class/infiniband_srp/srp-<hca>-<port_number>/ibdev Date: January 2, 2006 KernelVersion: 2.6.15 Contact: linux-rdma@vger.kernel.org Description: HCA name (<hca>). What: /sys/class/infiniband_srp/srp-<hca>-<port_number>/port Date: January 2, 2006 KernelVersion: 2.6.15 Contact: linux-rdma@vger.kernel.org Description: HCA port number (<port_number>). What: /sys/class/scsi_host/host<n>/allow_ext_sg Date: May 19, 2011 KernelVersion: 2.6.39 Contact: linux-rdma@vger.kernel.org Description: Whether ib_srp is allowed to include a partial memory descriptor list in an SRP_CMD when communicating with an SRP target. What: /sys/class/scsi_host/host<n>/cmd_sg_entries Date: May 19, 2011 KernelVersion: 2.6.39 Contact: linux-rdma@vger.kernel.org Description: Maximum number of data buffer descriptors that may be sent to the target in a single SRP_CMD request. What: /sys/class/scsi_host/host<n>/dgid Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: InfiniBand destination GID used for communication with the SRP target. Differs from orig_dgid if port redirection has happened. What: /sys/class/scsi_host/host<n>/id_ext Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: Eight-byte identifier extension portion of the 16-byte target port identifier. What: /sys/class/scsi_host/host<n>/ioc_guid Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: Eight-byte I/O controller GUID portion of the 16-byte target port identifier. What: /sys/class/scsi_host/host<n>/local_ib_device Date: November 29, 2006 KernelVersion: 2.6.19 Contact: linux-rdma@vger.kernel.org Description: Name of the InfiniBand HCA used for communicating with the SRP target. What: /sys/class/scsi_host/host<n>/local_ib_port Date: November 29, 2006 KernelVersion: 2.6.19 Contact: linux-rdma@vger.kernel.org Description: Number of the HCA port used for communicating with the SRP target. What: /sys/class/scsi_host/host<n>/orig_dgid Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: InfiniBand destination GID specified in the parameters written to the add_target sysfs attribute. What: /sys/class/scsi_host/host<n>/pkey Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: A 16-bit number representing the InfiniBand partition key used for communication with the SRP target. What: /sys/class/scsi_host/host<n>/req_lim Date: October 20, 2010 KernelVersion: 2.6.36 Contact: linux-rdma@vger.kernel.org Description: Number of requests ib_srp can send to the target before it has to wait for more credits. For more information see also the SRP credit algorithm in the SRP specification. What: /sys/class/scsi_host/host<n>/service_id Date: June 17, 2006 KernelVersion: 2.6.17 Contact: linux-rdma@vger.kernel.org Description: InfiniBand service ID used for establishing communication with the SRP target. What: /sys/class/scsi_host/host<n>/zero_req_lim Date: September 20, 2006 KernelVersion: 2.6.18 Contact: linux-rdma@vger.kernel.org Description: Number of times the initiator had to wait before sending a request to the target because it ran out of credits. For more information see also the SRP credit algorithm in the SRP specification.
Documentation/ABI/stable/sysfs-transport-srp 0 → 100644 +19 −0 Original line number Diff line number Diff line What: /sys/class/srp_remote_ports/port-<h>:<n>/delete Date: June 1, 2012 KernelVersion: 3.7 Contact: linux-scsi@vger.kernel.org, linux-rdma@vger.kernel.org Description: Instructs an SRP initiator to disconnect from a target and to remove all LUNs imported from that target. What: /sys/class/srp_remote_ports/port-<h>:<n>/port_id Date: June 27, 2007 KernelVersion: 2.6.24 Contact: linux-scsi@vger.kernel.org Description: 16-byte local SRP port identifier in hexadecimal format. An example: 4c:49:4e:55:58:20:56:49:4f:00:00:00:00:00:00:00. What: /sys/class/srp_remote_ports/port-<h>:<n>/roles Date: June 27, 2007 KernelVersion: 2.6.24 Contact: linux-scsi@vger.kernel.org Description: Role of the remote port. Either "SRP Initiator" or "SRP Target".
drivers/infiniband/ulp/srp/ib_srp.c +185 −129 Original line number Diff line number Diff line Loading @@ -222,27 +222,29 @@ static int srp_new_cm_id(struct srp_target_port *target) static int srp_create_target_ib(struct srp_target_port *target) { struct ib_qp_init_attr *init_attr; struct ib_cq *recv_cq, *send_cq; struct ib_qp *qp; int ret; init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); if (!init_attr) return -ENOMEM; target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); if (IS_ERR(target->recv_cq)) { ret = PTR_ERR(target->recv_cq); if (IS_ERR(recv_cq)) { ret = PTR_ERR(recv_cq); goto err; } target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev, send_cq = ib_create_cq(target->srp_host->srp_dev->dev, srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); if (IS_ERR(target->send_cq)) { ret = PTR_ERR(target->send_cq); if (IS_ERR(send_cq)) { ret = PTR_ERR(send_cq); goto err_recv_cq; } ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP); ib_req_notify_cq(recv_cq, IB_CQ_NEXT_COMP); init_attr->event_handler = srp_qp_event; init_attr->cap.max_send_wr = SRP_SQ_SIZE; Loading @@ -251,30 +253,41 @@ static int srp_create_target_ib(struct srp_target_port *target) init_attr->cap.max_send_sge = 1; init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; init_attr->qp_type = IB_QPT_RC; init_attr->send_cq = target->send_cq; init_attr->recv_cq = target->recv_cq; init_attr->send_cq = send_cq; init_attr->recv_cq = recv_cq; target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); if (IS_ERR(target->qp)) { ret = PTR_ERR(target->qp); qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); if (IS_ERR(qp)) { ret = PTR_ERR(qp); goto err_send_cq; } ret = srp_init_qp(target, target->qp); ret = srp_init_qp(target, qp); if (ret) goto err_qp; if (target->qp) ib_destroy_qp(target->qp); if (target->recv_cq) ib_destroy_cq(target->recv_cq); if (target->send_cq) ib_destroy_cq(target->send_cq); target->qp = qp; target->recv_cq = recv_cq; target->send_cq = send_cq; kfree(init_attr); return 0; err_qp: ib_destroy_qp(target->qp); ib_destroy_qp(qp); err_send_cq: ib_destroy_cq(target->send_cq); ib_destroy_cq(send_cq); err_recv_cq: ib_destroy_cq(target->recv_cq); ib_destroy_cq(recv_cq); err: kfree(init_attr); Loading @@ -289,6 +302,9 @@ static void srp_free_target_ib(struct srp_target_port *target) ib_destroy_cq(target->send_cq); ib_destroy_cq(target->recv_cq); target->qp = NULL; target->send_cq = target->recv_cq = NULL; for (i = 0; i < SRP_RQ_SIZE; ++i) srp_free_iu(target->srp_host, target->rx_ring[i]); for (i = 0; i < SRP_SQ_SIZE; ++i) Loading Loading @@ -428,34 +444,50 @@ static int srp_send_req(struct srp_target_port *target) return status; } static void srp_disconnect_target(struct srp_target_port *target) static bool srp_queue_remove_work(struct srp_target_port *target) { /* XXX should send SRP_I_LOGOUT request */ bool changed = false; init_completion(&target->done); if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { shost_printk(KERN_DEBUG, target->scsi_host, PFX "Sending CM DREQ failed\n"); return; spin_lock_irq(&target->lock); if (target->state != SRP_TARGET_REMOVED) { target->state = SRP_TARGET_REMOVED; changed = true; } wait_for_completion(&target->done); spin_unlock_irq(&target->lock); if (changed) queue_work(system_long_wq, &target->remove_work); return changed; } static bool srp_change_state(struct srp_target_port *target, enum srp_target_state old, enum srp_target_state new) static bool srp_change_conn_state(struct srp_target_port *target, bool connected) { bool changed = false; spin_lock_irq(&target->lock); if (target->state == old) { target->state = new; if (target->connected != connected) { target->connected = connected; changed = true; } spin_unlock_irq(&target->lock); return changed; } static void srp_disconnect_target(struct srp_target_port *target) { if (srp_change_conn_state(target, false)) { /* XXX should send SRP_I_LOGOUT request */ if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { shost_printk(KERN_DEBUG, target->scsi_host, PFX "Sending CM DREQ failed\n"); } } } static void srp_free_req_data(struct srp_target_port *target) { struct ib_device *ibdev = target->srp_host->srp_dev->dev; Loading Loading @@ -489,32 +521,50 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost) device_remove_file(&shost->shost_dev, *attr); } static void srp_remove_work(struct work_struct *work) static void srp_remove_target(struct srp_target_port *target) { struct srp_target_port *target = container_of(work, struct srp_target_port, work); if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED)) return; spin_lock(&target->srp_host->target_lock); list_del(&target->list); spin_unlock(&target->srp_host->target_lock); WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); srp_del_scsi_host_attr(target->scsi_host); srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); srp_free_req_data(target); scsi_host_put(target->scsi_host); } static void srp_remove_work(struct work_struct *work) { struct srp_target_port *target = container_of(work, struct srp_target_port, remove_work); WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); spin_lock(&target->srp_host->target_lock); list_del(&target->list); spin_unlock(&target->srp_host->target_lock); srp_remove_target(target); } static void srp_rport_delete(struct srp_rport *rport) { struct srp_target_port *target = rport->lld_data; srp_queue_remove_work(target); } static int srp_connect_target(struct srp_target_port *target) { int retries = 3; int ret; WARN_ON_ONCE(target->connected); target->qp_in_error = false; ret = srp_lookup_path(target); if (ret) return ret; Loading @@ -534,6 +584,7 @@ static int srp_connect_target(struct srp_target_port *target) */ switch (target->status) { case 0: srp_change_conn_state(target, true); return 0; case SRP_PORT_REDIRECT: Loading Loading @@ -646,13 +697,14 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re static int srp_reconnect_target(struct srp_target_port *target) { struct ib_qp_attr qp_attr; struct ib_wc wc; struct Scsi_Host *shost = target->scsi_host; int i, ret; if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) if (target->state != SRP_TARGET_LIVE) return -EAGAIN; scsi_target_block(&shost->shost_gendev); srp_disconnect_target(target); /* * Now get a new local CM ID so that we avoid confusing the Loading @@ -660,21 +712,11 @@ static int srp_reconnect_target(struct srp_target_port *target) */ ret = srp_new_cm_id(target); if (ret) goto err; qp_attr.qp_state = IB_QPS_RESET; ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE); if (ret) goto err; goto unblock; ret = srp_init_qp(target, target->qp); ret = srp_create_target_ib(target); if (ret) goto err; while (ib_poll_cq(target->recv_cq, 1, &wc) > 0) ; /* nothing */ while (ib_poll_cq(target->send_cq, 1, &wc) > 0) ; /* nothing */ goto unblock; for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { struct srp_request *req = &target->req_ring[i]; Loading @@ -686,13 +728,16 @@ static int srp_reconnect_target(struct srp_target_port *target) for (i = 0; i < SRP_SQ_SIZE; ++i) list_add(&target->tx_ring[i]->list, &target->free_tx); target->qp_in_error = 0; ret = srp_connect_target(target); unblock: scsi_target_unblock(&shost->shost_gendev, ret == 0 ? SDEV_RUNNING : SDEV_TRANSPORT_OFFLINE); if (ret) goto err; if (!srp_change_state(target, SRP_TARGET_CONNECTING, SRP_TARGET_LIVE)) ret = -EAGAIN; shost_printk(KERN_INFO, target->scsi_host, PFX "reconnect succeeded\n"); return ret; Loading @@ -705,17 +750,8 @@ static int srp_reconnect_target(struct srp_target_port *target) * However, we have to defer the real removal because we * are in the context of the SCSI error handler now, which * will deadlock if we call scsi_remove_host(). * * Schedule our work inside the lock to avoid a race with * the flush_scheduled_work() in srp_remove_one(). */ spin_lock_irq(&target->lock); if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; INIT_WORK(&target->work, srp_remove_work); queue_work(ib_wq, &target->work); } spin_unlock_irq(&target->lock); srp_queue_remove_work(target); return ret; } Loading Loading @@ -1262,6 +1298,19 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) PFX "Recv failed with error code %d\n", res); } static void srp_handle_qp_err(enum ib_wc_status wc_status, enum ib_wc_opcode wc_opcode, struct srp_target_port *target) { if (target->connected && !target->qp_in_error) { shost_printk(KERN_ERR, target->scsi_host, PFX "failed %s status %d\n", wc_opcode & IB_WC_RECV ? "receive" : "send", wc_status); } target->qp_in_error = true; } static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) { struct srp_target_port *target = target_ptr; Loading @@ -1269,15 +1318,11 @@ static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { shost_printk(KERN_ERR, target->scsi_host, PFX "failed receive status %d\n", wc.status); target->qp_in_error = 1; break; } if (likely(wc.status == IB_WC_SUCCESS)) { srp_handle_recv(target, &wc); } else { srp_handle_qp_err(wc.status, wc.opcode, target); } } } Loading @@ -1288,16 +1333,12 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) struct srp_iu *iu; while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { shost_printk(KERN_ERR, target->scsi_host, PFX "failed send status %d\n", wc.status); target->qp_in_error = 1; break; } if (likely(wc.status == IB_WC_SUCCESS)) { iu = (struct srp_iu *) (uintptr_t) wc.wr_id; list_add(&iu->list, &target->free_tx); } else { srp_handle_qp_err(wc.status, wc.opcode, target); } } } Loading @@ -1311,16 +1352,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) unsigned long flags; int len; if (target->state == SRP_TARGET_CONNECTING) goto err; if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) { scmnd->result = DID_BAD_TARGET << 16; scmnd->scsi_done(scmnd); return 0; } spin_lock_irqsave(&target->lock, flags); iu = __srp_get_tx_iu(target, SRP_IU_CMD); if (!iu) Loading Loading @@ -1377,7 +1408,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) err_unlock: spin_unlock_irqrestore(&target->lock, flags); err: return SCSI_MLQUEUE_HOST_BUSY; } Loading Loading @@ -1419,6 +1449,33 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target) return -ENOMEM; } static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) { uint64_t T_tr_ns, max_compl_time_ms; uint32_t rq_tmo_jiffies; /* * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, * table 91), both the QP timeout and the retry count have to be set * for RC QP's during the RTR to RTS transition. */ WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); /* * Set target->rq_tmo_jiffies to one second more than the largest time * it can take before an error completion is generated. See also * C9-140..142 in the IBTA spec for more information about how to * convert the QP Local ACK Timeout value to nanoseconds. */ T_tr_ns = 4096 * (1ULL << qp_attr->timeout); max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; do_div(max_compl_time_ms, NSEC_PER_MSEC); rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); return rq_tmo_jiffies; } static void srp_cm_rep_handler(struct ib_cm_id *cm_id, struct srp_login_rsp *lrsp, struct srp_target_port *target) Loading Loading @@ -1478,6 +1535,8 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id, if (ret) goto error_free; target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); ret = ib_modify_qp(target->qp, qp_attr, attr_mask); if (ret) goto error_free; Loading Loading @@ -1599,6 +1658,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) case IB_CM_DREQ_RECEIVED: shost_printk(KERN_WARNING, target->scsi_host, PFX "DREQ received - connection closed\n"); srp_change_conn_state(target, false); if (ib_send_cm_drep(cm_id, NULL, 0)) shost_printk(KERN_ERR, target->scsi_host, PFX "Sending CM DREP failed\n"); Loading @@ -1608,7 +1668,6 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) shost_printk(KERN_ERR, target->scsi_host, PFX "connection closed\n"); comp = 1; target->status = 0; break; Loading Loading @@ -1636,10 +1695,6 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -1; init_completion(&target->tsk_mgmt_done); spin_lock_irq(&target->lock); Loading Loading @@ -1729,6 +1784,21 @@ static int srp_reset_host(struct scsi_cmnd *scmnd) return ret; } static int srp_slave_configure(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->host; struct srp_target_port *target = host_to_target(shost); struct request_queue *q = sdev->request_queue; unsigned long timeout; if (sdev->type == TYPE_DISK) { timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); blk_queue_rq_timeout(q, timeout); } return 0; } static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, char *buf) { Loading Loading @@ -1861,6 +1931,7 @@ static struct scsi_host_template srp_template = { .module = THIS_MODULE, .name = "InfiniBand SRP initiator", .proc_name = DRV_NAME, .slave_configure = srp_slave_configure, .info = srp_target_info, .queuecommand = srp_queuecommand, .eh_abort_handler = srp_abort, Loading Loading @@ -1894,11 +1965,14 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target) return PTR_ERR(rport); } rport->lld_data = target; spin_lock(&host->target_lock); list_add_tail(&target->list, &host->target_list); spin_unlock(&host->target_lock); target->state = SRP_TARGET_LIVE; target->connected = false; scsi_scan_target(&target->scsi_host->shost_gendev, 0, target->scsi_id, SCAN_WILD_CARD, 0); Loading Loading @@ -2188,6 +2262,7 @@ static ssize_t srp_create_target(struct device *dev, sizeof (struct srp_indirect_buf) + target->cmd_sg_cnt * sizeof (struct srp_direct_buf); INIT_WORK(&target->remove_work, srp_remove_work); spin_lock_init(&target->lock); INIT_LIST_HEAD(&target->free_tx); INIT_LIST_HEAD(&target->free_reqs); Loading Loading @@ -2232,7 +2307,6 @@ static ssize_t srp_create_target(struct device *dev, if (ret) goto err_free_ib; target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) { shost_printk(KERN_ERR, target->scsi_host, Loading Loading @@ -2422,8 +2496,7 @@ static void srp_remove_one(struct ib_device *device) { struct srp_device *srp_dev; struct srp_host *host, *tmp_host; LIST_HEAD(target_list); struct srp_target_port *target, *tmp_target; struct srp_target_port *target; srp_dev = ib_get_client_data(device, &srp_client); Loading @@ -2436,35 +2509,17 @@ static void srp_remove_one(struct ib_device *device) wait_for_completion(&host->released); /* * Mark all target ports as removed, so we stop queueing * commands and don't try to reconnect. * Remove all target ports. */ spin_lock(&host->target_lock); list_for_each_entry(target, &host->target_list, list) { spin_lock_irq(&target->lock); target->state = SRP_TARGET_REMOVED; spin_unlock_irq(&target->lock); } list_for_each_entry(target, &host->target_list, list) srp_queue_remove_work(target); spin_unlock(&host->target_lock); /* * Wait for any reconnection tasks that may have * started before we marked our target ports as * removed, and any target port removal tasks. * Wait for target port removal tasks. */ flush_workqueue(ib_wq); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { srp_del_scsi_host_attr(target->scsi_host); srp_remove_host(target->scsi_host); scsi_remove_host(target->scsi_host); srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); srp_free_req_data(target); scsi_host_put(target->scsi_host); } flush_workqueue(system_long_wq); kfree(host); } Loading @@ -2478,6 +2533,7 @@ static void srp_remove_one(struct ib_device *device) } static struct srp_function_template ib_srp_transport_functions = { .rport_delete = srp_rport_delete, }; static int __init srp_init_module(void) Loading
drivers/infiniband/ulp/srp/ib_srp.h +6 −5 Original line number Diff line number Diff line Loading @@ -80,9 +80,7 @@ enum { enum srp_target_state { SRP_TARGET_LIVE, SRP_TARGET_CONNECTING, SRP_TARGET_DEAD, SRP_TARGET_REMOVED SRP_TARGET_REMOVED, }; enum srp_iu_type { Loading Loading @@ -163,6 +161,9 @@ struct srp_target_port { struct ib_sa_query *path_query; int path_query_id; u32 rq_tmo_jiffies; bool connected; struct ib_cm_id *cm_id; int max_ti_iu_len; Loading @@ -173,12 +174,12 @@ struct srp_target_port { struct srp_iu *rx_ring[SRP_RQ_SIZE]; struct srp_request req_ring[SRP_CMD_SQ_SIZE]; struct work_struct work; struct work_struct remove_work; struct list_head list; struct completion done; int status; int qp_in_error; bool qp_in_error; struct completion tsk_mgmt_done; u8 tsk_mgmt_status; Loading
drivers/scsi/scsi_transport_srp.c +27 −24 File changed.Preview size limit exceeded, changes collapsed. Show changes