⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ib_srp.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 + -