📄 ib_srp.c
字号:
/* * 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_MAX_CMD_PER_LUN = 1 << 6, SRP_OPT_IO_CLASS = 1 << 7, SRP_OPT_INITIATOR_EXT = 1 << 8, 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_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, { SRP_OPT_IO_CLASS, "io_class=%x" }, { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, { 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); if (!p) { ret = -ENOMEM; goto out; } target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_IOC_GUID: p = match_strdup(args); if (!p) { ret = -ENOMEM; goto out; } target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); break; case SRP_OPT_DGID: p = match_strdup(args); if (!p) { ret = -ENOMEM; goto out; } if (strlen(p) != 32) { printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); kfree(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); } kfree(p); memcpy(target->orig_dgid, target->path.dgid.raw, 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); if (!p) { ret = -ENOMEM; goto out; } target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); target->path.service_id = target->service_id; 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; case SRP_OPT_MAX_CMD_PER_LUN: if (match_int(args, &token)) { printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p); goto out; } target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE); break; case SRP_OPT_IO_CLASS: if (match_hex(args, &token)) { printk(KERN_WARNING PFX "bad IO class parameter '%s' \n", p); goto out; } if (token != SRP_REV10_IB_IO_CLASS && token != SRP_REV16A_IB_IO_CLASS) { printk(KERN_WARNING PFX "unknown IO class parameter value" " %x specified (use %x or %x).\n", token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS); goto out; } target->io_class = token; break; case SRP_OPT_INITIATOR_EXT: p = match_strdup(args); if (!p) { ret = -ENOMEM; goto out; } target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); kfree(p); 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->transportt = ib_srp_transport_template; target_host->max_lun = SRP_MAX_LUN; target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; target = host_to_target(target_host); target->io_class = SRP_REV16A_IB_IO_CLASS; target->scsi_host = target_host; target->srp_host = host; INIT_LIST_HEAD(&target->free_reqs); INIT_LIST_HEAD(&target->req_queue); for (i = 0; i < SRP_SQ_SIZE; ++i) { target->req_ring[i].index = i; list_add_tail(&target->req_ring[i].list, &target->free_reqs); } ret = srp_parse_options(buf, target); if (ret) goto err; ib_get_cached_gid(host->dev->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->dev, srp_cm_handler, target); if (IS_ERR(target->cm_id)) { ret = PTR_ERR(target->cm_id); goto err_free; } target->qp_in_error = 0; 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->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 srp_device *device, u8 port){ struct srp_host *host; host = kzalloc(sizeof *host, GFP_KERNEL); if (!host) return NULL; INIT_LIST_HEAD(&host->target_list); spin_lock_init(&host->target_lock); init_completion(&host->released); host->dev = device; host->port = port; host->class_dev.class = &srp_class; host->class_dev.dev = device->dev->dma_device; snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d", device->dev->name, port); if (class_device_register(&host->class_dev)) goto free_host; 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);free_host: kfree(host); return NULL;}static void srp_add_one(struct ib_device *device){ struct srp_device *srp_dev; struct ib_device_attr *dev_attr; struct ib_fmr_pool_param fmr_param; struct srp_host *host; 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 "Query device failed for %s\n", device->name); goto free_attr; } srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL); if (!srp_dev) goto free_attr; /* * Use the smallest page size supported by the HCA, down to a * minimum of 512 bytes (which is the smallest sector that a * SCSI command will ever carry). */ srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1); srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift; srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1); INIT_LIST_HEAD(&srp_dev->dev_list); srp_dev->dev = device; srp_dev->pd = ib_alloc_pd(device); if (IS_ERR(srp_dev->pd)) goto free_dev; srp_dev->mr = ib_get_dma_mr(srp_dev->pd, IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE); if (IS_ERR(srp_dev->mr)) goto err_pd; memset(&fmr_param, 0, sizeof fmr_param); fmr_param.pool_size = SRP_FMR_POOL_SIZE; fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; fmr_param.cache = 1; fmr_param.max_pages_per_fmr = SRP_FMR_SIZE; fmr_param.page_shift = srp_dev->fmr_page_shift; fmr_param.access = (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ); srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); if (IS_ERR(srp_dev->fmr_pool)) srp_dev->fmr_pool = NULL; if (device->node_type == RDMA_NODE_IB_SWITCH) { s = 0; e = 0; } else { s = 1; e = device->phys_port_cnt; } for (p = s; p <= e; ++p) { host = srp_add_port(srp_dev, p); if (host) list_add_tail(&host->list, &srp_dev->dev_list); } ib_set_client_data(device, &srp_client, srp_dev); goto free_attr;err_pd: ib_dealloc_pd(srp_dev->pd);free_dev: kfree(srp_dev);free_attr: kfree(dev_attr);}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; srp_dev = ib_get_client_data(device, &srp_client); list_for_each_entry_safe(host, tmp_host, &srp_dev->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. */ spin_lock(&host->target_lock); list_for_each_entry(target, &host->target_list, list) { spin_lock_irq(target->scsi_host->host_lock); target->state = SRP_TARGET_REMOVED; spin_unlock_irq(target->scsi_host->host_lock); } 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. */ flush_scheduled_work(); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { 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); scsi_host_put(target->scsi_host); } kfree(host); } if (srp_dev->fmr_pool) ib_destroy_fmr_pool(srp_dev->fmr_pool); ib_dereg_mr(srp_dev->mr); ib_dealloc_pd(srp_dev->pd); kfree(srp_dev);}static struct srp_function_template ib_srp_transport_functions = {};static int __init srp_init_module(void){ int ret; ib_srp_transport_template = srp_attach_transport(&ib_srp_transport_functions); if (!ib_srp_transport_template) return -ENOMEM; srp_template.sg_tablesize = srp_sg_tablesize; srp_max_iu_len = (sizeof (struct srp_cmd) + sizeof (struct srp_indirect_buf) + srp_sg_tablesize * 16); ret = class_register(&srp_class); if (ret) { printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); srp_release_transport(ib_srp_transport_template); return ret; } ib_sa_register_client(&srp_sa_client); ret = ib_register_client(&srp_client); if (ret) { printk(KERN_ERR PFX "couldn't register IB client\n"); srp_release_transport(ib_srp_transport_template); ib_sa_unregister_client(&srp_sa_client); class_unregister(&srp_class); return ret; } return 0;}static void __exit srp_cleanup_module(void){ ib_unregister_client(&srp_client); ib_sa_unregister_client(&srp_sa_client); class_unregister(&srp_class); srp_release_transport(ib_srp_transport_template);}module_init(srp_init_module);module_exit(srp_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -