📄 ib_srp.c
字号:
} for (i = 0; i < SRP_SQ_SIZE + 1; ++i) { target->tx_ring[i] = srp_alloc_iu(target->srp_host, srp_max_iu_len, GFP_KERNEL, DMA_TO_DEVICE); if (!target->tx_ring[i]) goto err; } return 0;err: for (i = 0; i < SRP_RQ_SIZE; ++i) { srp_free_iu(target->srp_host, target->rx_ring[i]); target->rx_ring[i] = NULL; } for (i = 0; i < SRP_SQ_SIZE + 1; ++i) { srp_free_iu(target->srp_host, target->tx_ring[i]); target->tx_ring[i] = NULL; } return -ENOMEM;}static void srp_cm_rej_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event, struct srp_target_port *target){ struct ib_class_port_info *cpi; int opcode; switch (event->param.rej_rcvd.reason) { case IB_CM_REJ_PORT_CM_REDIRECT: cpi = event->param.rej_rcvd.ari; target->path.dlid = cpi->redirect_lid; target->path.pkey = cpi->redirect_pkey; cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; memcpy(target->path.dgid.raw, cpi->redirect_gid, 16); target->status = target->path.dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; break; case IB_CM_REJ_PORT_REDIRECT: if (srp_target_is_topspin(target)) { /* * Topspin/Cisco SRP gateways incorrectly send * reject reason code 25 when they mean 24 * (port redirect). */ memcpy(target->path.dgid.raw, event->param.rej_rcvd.ari, 16); printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); target->status = SRP_PORT_REDIRECT; } else { printk(KERN_WARNING " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); target->status = -ECONNRESET; } break; case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: printk(KERN_WARNING " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); target->status = -ECONNRESET; break; case IB_CM_REJ_CONSUMER_DEFINED: opcode = *(u8 *) event->private_data; if (opcode == SRP_LOGIN_REJ) { struct srp_login_rej *rej = event->private_data; u32 reason = be32_to_cpu(rej->reason); if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) printk(KERN_WARNING PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); else printk(KERN_WARNING PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); } else printk(KERN_WARNING " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," " opcode 0x%02x\n", opcode); target->status = -ECONNRESET; break; default: printk(KERN_WARNING " REJ reason 0x%x\n", event->param.rej_rcvd.reason); target->status = -ECONNRESET; }}static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event){ struct srp_target_port *target = cm_id->context; struct ib_qp_attr *qp_attr = NULL; int attr_mask = 0; int comp = 0; int opcode = 0; switch (event->event) { case IB_CM_REQ_ERROR: printk(KERN_DEBUG PFX "Sending CM REQ failed\n"); comp = 1; target->status = -ECONNRESET; break; case IB_CM_REP_RECEIVED: comp = 1; opcode = *(u8 *) event->private_data; if (opcode == SRP_LOGIN_RSP) { struct srp_login_rsp *rsp = event->private_data; target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len); target->req_lim = be32_to_cpu(rsp->req_lim_delta); target->scsi_host->can_queue = min(target->req_lim, target->scsi_host->can_queue); } else { printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode); target->status = -ECONNRESET; break; } if (!target->rx_ring[0]) { target->status = srp_alloc_iu_bufs(target); if (target->status) break; } qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); if (!qp_attr) { target->status = -ENOMEM; break; } qp_attr->qp_state = IB_QPS_RTR; target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); if (target->status) break; target->status = ib_modify_qp(target->qp, qp_attr, attr_mask); if (target->status) break; target->status = srp_post_recv(target); if (target->status) break; qp_attr->qp_state = IB_QPS_RTS; target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); if (target->status) break; target->status = ib_modify_qp(target->qp, qp_attr, attr_mask); if (target->status) break; target->status = ib_send_cm_rtu(cm_id, NULL, 0); if (target->status) break; break; case IB_CM_REJ_RECEIVED: printk(KERN_DEBUG PFX "REJ received\n"); comp = 1; srp_cm_rej_handler(cm_id, event, target); break; case IB_CM_DREQ_RECEIVED: printk(KERN_WARNING PFX "DREQ received - connection closed\n"); if (ib_send_cm_drep(cm_id, NULL, 0)) printk(KERN_ERR PFX "Sending CM DREP failed\n"); break; case IB_CM_TIMEWAIT_EXIT: printk(KERN_ERR PFX "connection closed\n"); comp = 1; target->status = 0; break; case IB_CM_MRA_RECEIVED: case IB_CM_DREQ_ERROR: case IB_CM_DREP_RECEIVED: break; default: printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event); break; } if (comp) complete(&target->done); kfree(qp_attr); return 0;}static int srp_send_tsk_mgmt(struct srp_target_port *target, struct srp_request *req, u8 func){ struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; spin_lock_irq(target->scsi_host->host_lock); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) { req->scmnd->result = DID_BAD_TARGET << 16; goto out; } init_completion(&req->done); iu = __srp_get_tx_iu(target); if (!iu) goto out; tsk_mgmt = iu->buf; memset(tsk_mgmt, 0, sizeof *tsk_mgmt); tsk_mgmt->opcode = SRP_TSK_MGMT; tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; tsk_mgmt->tsk_mgmt_func = func; tsk_mgmt->task_tag = req->index; if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) goto out; req->tsk_mgmt = iu; spin_unlock_irq(target->scsi_host->host_lock); if (!wait_for_completion_timeout(&req->done, msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) return -1; return 0;out: spin_unlock_irq(target->scsi_host->host_lock); return -1;}static int srp_find_req(struct srp_target_port *target, struct scsi_cmnd *scmnd, struct srp_request **req){ if (scmnd->host_scribble == (void *) -1L) return -1; *req = &target->req_ring[(long) scmnd->host_scribble]; return 0;}static int srp_abort(struct scsi_cmnd *scmnd){ struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req; int ret = SUCCESS; printk(KERN_ERR "SRP abort called\n"); if (target->qp_in_error) return FAILED; if (srp_find_req(target, scmnd, &req)) return FAILED; if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) return FAILED; spin_lock_irq(target->scsi_host->host_lock); if (req->cmd_done) { srp_remove_req(target, req); scmnd->scsi_done(scmnd); } else if (!req->tsk_status) { srp_remove_req(target, req); scmnd->result = DID_ABORT << 16; } else ret = FAILED; spin_unlock_irq(target->scsi_host->host_lock); return ret;}static int srp_reset_device(struct scsi_cmnd *scmnd){ struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req, *tmp; printk(KERN_ERR "SRP reset_device called\n"); if (target->qp_in_error) return FAILED; if (srp_find_req(target, scmnd, &req)) return FAILED; if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) return FAILED; if (req->tsk_status) return FAILED; spin_lock_irq(target->scsi_host->host_lock); list_for_each_entry_safe(req, tmp, &target->req_queue, list) if (req->scmnd->device == scmnd->device) srp_reset_req(target, req); spin_unlock_irq(target->scsi_host->host_lock); return SUCCESS;}static int srp_reset_host(struct scsi_cmnd *scmnd){ struct srp_target_port *target = host_to_target(scmnd->device->host); int ret = FAILED; printk(KERN_ERR PFX "SRP reset_host called\n"); if (!srp_reconnect_target(target)) ret = SUCCESS; return ret;}static ssize_t show_id_ext(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "0x%016llx\n", (unsigned long long) be64_to_cpu(target->id_ext));}static ssize_t show_ioc_guid(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "0x%016llx\n", (unsigned long long) be64_to_cpu(target->ioc_guid));}static ssize_t show_service_id(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "0x%016llx\n", (unsigned long long) be64_to_cpu(target->service_id));}static ssize_t show_pkey(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey));}static ssize_t show_dgid(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]), be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));}static ssize_t show_orig_dgid(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", be16_to_cpu(target->orig_dgid[0]), be16_to_cpu(target->orig_dgid[1]), be16_to_cpu(target->orig_dgid[2]), be16_to_cpu(target->orig_dgid[3]), be16_to_cpu(target->orig_dgid[4]), be16_to_cpu(target->orig_dgid[5]), be16_to_cpu(target->orig_dgid[6]), be16_to_cpu(target->orig_dgid[7]));}static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); if (target->state == SRP_TARGET_DEAD || target->state == SRP_TARGET_REMOVED) return -ENODEV; return sprintf(buf, "%d\n", target->zero_req_lim);}static ssize_t show_local_ib_port(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); return sprintf(buf, "%d\n", target->srp_host->port);}static ssize_t show_local_ib_device(struct class_device *cdev, char *buf){ struct srp_target_port *target = host_to_target(class_to_shost(cdev)); return sprintf(buf, "%s\n", target->srp_host->dev->dev->name);}static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);static CLASS_DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL);static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);static CLASS_DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);static struct class_device_attribute *srp_host_attrs[] = { &class_device_attr_id_ext, &class_device_attr_ioc_guid, &class_device_attr_service_id, &class_device_attr_pkey, &class_device_attr_dgid, &class_device_attr_orig_dgid, &class_device_attr_zero_req_lim, &class_device_attr_local_ib_port, &class_device_attr_local_ib_device, NULL};static struct scsi_host_template srp_template = { .module = THIS_MODULE, .name = "InfiniBand SRP initiator", .proc_name = DRV_NAME, .info = srp_target_info, .queuecommand = srp_queuecommand, .eh_abort_handler = srp_abort, .eh_device_reset_handler = srp_reset_device, .eh_host_reset_handler = srp_reset_host, .can_queue = SRP_SQ_SIZE, .this_id = -1, .cmd_per_lun = SRP_SQ_SIZE, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = srp_host_attrs};static int srp_add_target(struct srp_host *host, struct srp_target_port *target){ struct srp_rport_identifiers ids; struct srp_rport *rport; sprintf(target->target_name, "SRP.T10:%016llX", (unsigned long long) be64_to_cpu(target->id_ext)); if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device)) return -ENODEV; memcpy(ids.port_id, &target->id_ext, 8); memcpy(ids.port_id + 8, &target->ioc_guid, 8); ids.roles = SRP_RPORT_ROLE_TARGET; rport = srp_rport_add(target->scsi_host, &ids); if (IS_ERR(rport)) { scsi_remove_host(target->scsi_host); return PTR_ERR(rport); } spin_lock(&host->target_lock); list_add_tail(&target->list, &host->target_list); spin_unlock(&host->target_lock); target->state = SRP_TARGET_LIVE; scsi_scan_target(&target->scsi_host->shost_gendev, 0, target->scsi_id, SCAN_WILD_CARD, 0); return 0;}static void srp_release_class_dev(struct class_device *class_dev){ struct srp_host *host = container_of(class_dev, struct srp_host, class_dev); complete(&host->released);}static struct class srp_class = { .name = "infiniband_srp", .release = srp_release_class_dev};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -