📄 ib_srp.c
字号:
complete(&target->done); kfree(qp_attr); return 0;}static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func){ struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req; struct srp_iu *iu; struct srp_tsk_mgmt *tsk_mgmt; int req_index; int ret = FAILED; spin_lock_irq(target->scsi_host->host_lock); if (scmnd->host_scribble == (void *) -1L) goto out; req_index = (long) scmnd->host_scribble; printk(KERN_ERR "Abort for req_index %d\n", req_index); req = &target->req_ring[req_index]; 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) 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 FAILED; spin_lock_irq(target->scsi_host->host_lock); if (req->cmd_done) { list_del(&req->list); req->next = target->req_head; target->req_head = req_index; scmnd->scsi_done(scmnd); } else if (!req->tsk_status) { scmnd->result = DID_ABORT << 16; ret = SUCCESS; }out: spin_unlock_irq(target->scsi_host->host_lock); return ret;}static int srp_abort(struct scsi_cmnd *scmnd){ printk(KERN_ERR "SRP abort called\n"); return srp_send_tsk_mgmt(scmnd, SRP_TSK_ABORT_TASK);}static int srp_reset_device(struct scsi_cmnd *scmnd){ printk(KERN_ERR "SRP reset_device called\n"); return srp_send_tsk_mgmt(scmnd, SRP_TSK_LUN_RESET);}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 struct scsi_host_template srp_template = { .module = THIS_MODULE, .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, .sg_tablesize = SRP_MAX_INDIRECT, .cmd_per_lun = SRP_SQ_SIZE, .use_clustering = ENABLE_CLUSTERING};static int srp_add_target(struct srp_host *host, struct srp_target_port *target){ 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->dma_device)) return -ENODEV; down(&host->target_mutex); list_add_tail(&target->list, &host->target_list); up(&host->target_mutex); target->state = SRP_TARGET_LIVE; /* XXX: are we supposed to have a definition of SCAN_WILD_CARD ?? */ scsi_scan_target(&target->scsi_host->shost_gendev, 0, target->scsi_id, ~0, 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};/* * Target ports are added by writing * * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, * pkey=<P_Key>,service_id=<service ID> * * to the add_target sysfs attribute. */enum { SRP_OPT_ERR = 0, SRP_OPT_ID_EXT = 1 << 0, SRP_OPT_IOC_GUID = 1 << 1, SRP_OPT_DGID = 1 << 2, SRP_OPT_PKEY = 1 << 3, SRP_OPT_SERVICE_ID = 1 << 4, SRP_OPT_MAX_SECT = 1 << 5, SRP_OPT_ALL = (SRP_OPT_ID_EXT | SRP_OPT_IOC_GUID | SRP_OPT_DGID | SRP_OPT_PKEY | SRP_OPT_SERVICE_ID),};static match_table_t srp_opt_tokens = { { SRP_OPT_ID_EXT, "id_ext=%s" }, { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, { SRP_OPT_DGID, "dgid=%s" }, { SRP_OPT_PKEY, "pkey=%x" }, { SRP_OPT_SERVICE_ID, "service_id=%s" }, { SRP_OPT_MAX_SECT, "max_sect=%d" }, { SRP_OPT_ERR, NULL }};static int srp_parse_options(const char *buf, struct srp_target_port *target){ char *options, *sep_opt; char *p; char dgid[3]; substring_t args[MAX_OPT_ARGS]; int opt_mask = 0; int token; int ret = -EINVAL; int i; options = kstrdup(buf, GFP_KERNEL); if (!options) return -ENOMEM; sep_opt = options; while ((p = strsep(&sep_opt, ",")) != NULL) { if (!*p) continue; token = match_token(p, srp_opt_tokens, args); opt_mask |= token; switch (token) { case SRP_OPT_ID_EXT: p = match_strdup(args); target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_IOC_GUID: p = match_strdup(args); target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_DGID: p = match_strdup(args); if (strlen(p) != 32) { printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); goto out; } for (i = 0; i < 16; ++i) { strlcpy(dgid, p + i * 2, 3); target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); } break; case SRP_OPT_PKEY: if (match_hex(args, &token)) { printk(KERN_WARNING PFX "bad P_Key parameter '%s'\n", p); goto out; } target->path.pkey = cpu_to_be16(token); break; case SRP_OPT_SERVICE_ID: p = match_strdup(args); target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_MAX_SECT: if (match_int(args, &token)) { printk(KERN_WARNING PFX "bad max sect parameter '%s'\n", p); goto out; } target->scsi_host->max_sectors = token; break; default: printk(KERN_WARNING PFX "unknown parameter or missing value " "'%s' in target creation request\n", p); goto out; } } if ((opt_mask & SRP_OPT_ALL) == SRP_OPT_ALL) ret = 0; else for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i) if ((srp_opt_tokens[i].token & SRP_OPT_ALL) && !(srp_opt_tokens[i].token & opt_mask)) printk(KERN_WARNING PFX "target creation request is " "missing parameter '%s'\n", srp_opt_tokens[i].pattern);out: kfree(options); return ret;}static ssize_t srp_create_target(struct class_device *class_dev, const char *buf, size_t count){ struct srp_host *host = container_of(class_dev, struct srp_host, class_dev); struct Scsi_Host *target_host; struct srp_target_port *target; int ret; int i; target_host = scsi_host_alloc(&srp_template, sizeof (struct srp_target_port)); if (!target_host) return -ENOMEM; target_host->max_lun = SRP_MAX_LUN; target = host_to_target(target_host); memset(target, 0, sizeof *target); target->scsi_host = target_host; target->srp_host = host; INIT_WORK(&target->work, srp_reconnect_work, target); for (i = 0; i < SRP_SQ_SIZE - 1; ++i) target->req_ring[i].next = i + 1; target->req_ring[SRP_SQ_SIZE - 1].next = -1; INIT_LIST_HEAD(&target->req_queue); ret = srp_parse_options(buf, target); if (ret) goto err; ib_get_cached_gid(host->dev, host->port, 0, &target->path.sgid); printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", (unsigned long long) be64_to_cpu(target->id_ext), (unsigned long long) be64_to_cpu(target->ioc_guid), be16_to_cpu(target->path.pkey), (unsigned long long) be64_to_cpu(target->service_id), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[0]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[2]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[4]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[6]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[8]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[10]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[12]), (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[14])); ret = srp_create_target_ib(target); if (ret) goto err; target->cm_id = ib_create_cm_id(host->dev, srp_cm_handler, target); if (IS_ERR(target->cm_id)) { ret = PTR_ERR(target->cm_id); goto err_free; } ret = srp_connect_target(target); if (ret) { printk(KERN_ERR PFX "Connection failed\n"); goto err_cm_id; } ret = srp_add_target(host, target); if (ret) goto err_disconnect; return count;err_disconnect: srp_disconnect_target(target);err_cm_id: ib_destroy_cm_id(target->cm_id);err_free: srp_free_target_ib(target);err: scsi_host_put(target_host); return ret;}static CLASS_DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target);static ssize_t show_ibdev(struct class_device *class_dev, char *buf){ struct srp_host *host = container_of(class_dev, struct srp_host, class_dev); return sprintf(buf, "%s\n", host->dev->name);}static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);static ssize_t show_port(struct class_device *class_dev, char *buf){ struct srp_host *host = container_of(class_dev, struct srp_host, class_dev); return sprintf(buf, "%d\n", host->port);}static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);static struct srp_host *srp_add_port(struct ib_device *device, __be64 node_guid, u8 port){ struct srp_host *host; host = kzalloc(sizeof *host, GFP_KERNEL); if (!host) return NULL; INIT_LIST_HEAD(&host->target_list); init_MUTEX(&host->target_mutex); init_completion(&host->released); host->dev = device; host->port = port; host->initiator_port_id[7] = port; memcpy(host->initiator_port_id + 8, &node_guid, 8); host->pd = ib_alloc_pd(device); if (IS_ERR(host->pd)) goto err_free; host->mr = ib_get_dma_mr(host->pd, IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE); if (IS_ERR(host->mr)) goto err_pd; host->class_dev.class = &srp_class; host->class_dev.dev = device->dma_device; snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d", device->name, port); if (class_device_register(&host->class_dev)) goto err_mr; if (class_device_create_file(&host->class_dev, &class_device_attr_add_target)) goto err_class; if (class_device_create_file(&host->class_dev, &class_device_attr_ibdev)) goto err_class; if (class_device_create_file(&host->class_dev, &class_device_attr_port)) goto err_class; return host;err_class: class_device_unregister(&host->class_dev);err_mr: ib_dereg_mr(host->mr);err_pd: ib_dealloc_pd(host->pd);err_free: kfree(host); return NULL;}static void srp_add_one(struct ib_device *device){ struct list_head *dev_list; struct srp_host *host; struct ib_device_attr *dev_attr; int s, e, p; dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); if (!dev_attr) return; if (ib_query_device(device, dev_attr)) { printk(KERN_WARNING PFX "Couldn't query node GUID for %s.\n", device->name); goto out; } dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL); if (!dev_list) goto out; INIT_LIST_HEAD(dev_list); if (device->node_type == IB_NODE_SWITCH) { s = 0; e = 0; } else { s = 1; e = device->phys_port_cnt; } for (p = s; p <= e; ++p) { host = srp_add_port(device, dev_attr->node_guid, p); if (host) list_add_tail(&host->list, dev_list); } ib_set_client_data(device, &srp_client, dev_list);out: kfree(dev_attr);}static void srp_remove_one(struct ib_device *device){ struct list_head *dev_list; struct srp_host *host, *tmp_host; LIST_HEAD(target_list); struct srp_target_port *target, *tmp_target; unsigned long flags; dev_list = ib_get_client_data(device, &srp_client); list_for_each_entry_safe(host, tmp_host, dev_list, list) { class_device_unregister(&host->class_dev); /* * Wait for the sysfs entry to go away, so that no new * target ports can be created. */ wait_for_completion(&host->released); /* * Mark all target ports as removed, so we stop queueing * commands and don't try to reconnect. */ down(&host->target_mutex); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { spin_lock_irqsave(target->scsi_host->host_lock, flags); if (target->state != SRP_TARGET_REMOVED) target->state = SRP_TARGET_REMOVED; spin_unlock_irqrestore(target->scsi_host->host_lock, flags); } up(&host->target_mutex); /* * Wait for any reconnection tasks that may have * started before we marked our target ports as * removed, and any target port removal tasks. */ flush_scheduled_work(); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { scsi_remove_host(target->scsi_host); srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); scsi_host_put(target->scsi_host); } ib_dereg_mr(host->mr); ib_dealloc_pd(host->pd); kfree(host); } kfree(dev_list);}static int __init srp_init_module(void){ int ret; ret = class_register(&srp_class); if (ret) { printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); return ret; } ret = ib_register_client(&srp_client); if (ret) { printk(KERN_ERR PFX "couldn't register IB client\n"); class_unregister(&srp_class); return ret; } return 0;}static void __exit srp_cleanup_module(void){ ib_unregister_client(&srp_client); class_unregister(&srp_class);}module_init(srp_init_module);module_exit(srp_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -