scsi_transport_spi.c

来自「linux 内核源代码」· C语言 代码 · 共 1,441 行 · 第 1/3 页

C
1,441
字号
	scsi_target_resume(starget);	spi_initial_dv(starget) = 1; out_free:	kfree(buffer); out_put:	spi_dv_in_progress(starget) = 0;	scsi_device_put(sdev);}EXPORT_SYMBOL(spi_dv_device);struct work_queue_wrapper {	struct work_struct	work;	struct scsi_device	*sdev;};static voidspi_dv_device_work_wrapper(struct work_struct *work){	struct work_queue_wrapper *wqw =		container_of(work, struct work_queue_wrapper, work);	struct scsi_device *sdev = wqw->sdev;	kfree(wqw);	spi_dv_device(sdev);	spi_dv_pending(sdev->sdev_target) = 0;	scsi_device_put(sdev);}/** *	spi_schedule_dv_device - schedule domain validation to occur on the device *	@sdev:	The device to validate * *	Identical to spi_dv_device() above, except that the DV will be *	scheduled to occur in a workqueue later.  All memory allocations *	are atomic, so may be called from any context including those holding *	SCSI locks. */voidspi_schedule_dv_device(struct scsi_device *sdev){	struct work_queue_wrapper *wqw =		kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC);	if (unlikely(!wqw))		return;	if (unlikely(spi_dv_pending(sdev->sdev_target))) {		kfree(wqw);		return;	}	/* Set pending early (dv_device doesn't check it, only sets it) */	spi_dv_pending(sdev->sdev_target) = 1;	if (unlikely(scsi_device_get(sdev))) {		kfree(wqw);		spi_dv_pending(sdev->sdev_target) = 0;		return;	}	INIT_WORK(&wqw->work, spi_dv_device_work_wrapper);	wqw->sdev = sdev;	schedule_work(&wqw->work);}EXPORT_SYMBOL(spi_schedule_dv_device);/** * spi_display_xfer_agreement - Print the current target transfer agreement * @starget: The target for which to display the agreement * * Each SPI port is required to maintain a transfer agreement for each * other port on the bus.  This function prints a one-line summary of * the current agreement; more detailed information is available in sysfs. */void spi_display_xfer_agreement(struct scsi_target *starget){	struct spi_transport_attrs *tp;	tp = (struct spi_transport_attrs *)&starget->starget_data;	if (tp->offset > 0 && tp->period > 0) {		unsigned int picosec, kb100;		char *scsi = "FAST-?";		char tmp[8];		if (tp->period <= SPI_STATIC_PPR) {			picosec = ppr_to_ps[tp->period];			switch (tp->period) {				case  7: scsi = "FAST-320"; break;				case  8: scsi = "FAST-160"; break;				case  9: scsi = "FAST-80"; break;				case 10:				case 11: scsi = "FAST-40"; break;				case 12: scsi = "FAST-20"; break;			}		} else {			picosec = tp->period * 4000;			if (tp->period < 25)				scsi = "FAST-20";			else if (tp->period < 50)				scsi = "FAST-10";			else				scsi = "FAST-5";		}		kb100 = (10000000 + picosec / 2) / picosec;		if (tp->width)			kb100 *= 2;		sprint_frac(tmp, picosec, 1000);		dev_info(&starget->dev,			 "%s %sSCSI %d.%d MB/s %s%s%s%s%s%s%s%s (%s ns, offset %d)\n",			 scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,			 tp->dt ? "DT" : "ST",			 tp->iu ? " IU" : "",			 tp->qas  ? " QAS" : "",			 tp->rd_strm ? " RDSTRM" : "",			 tp->rti ? " RTI" : "",			 tp->wr_flow ? " WRFLOW" : "",			 tp->pcomp_en ? " PCOMP" : "",			 tp->hold_mcs ? " HMCS" : "",			 tmp, tp->offset);	} else {		dev_info(&starget->dev, "%sasynchronous\n",				tp->width ? "wide " : "");	}}EXPORT_SYMBOL(spi_display_xfer_agreement);int spi_populate_width_msg(unsigned char *msg, int width){	msg[0] = EXTENDED_MESSAGE;	msg[1] = 2;	msg[2] = EXTENDED_WDTR;	msg[3] = width;	return 4;}EXPORT_SYMBOL_GPL(spi_populate_width_msg);int spi_populate_sync_msg(unsigned char *msg, int period, int offset){	msg[0] = EXTENDED_MESSAGE;	msg[1] = 3;	msg[2] = EXTENDED_SDTR;	msg[3] = period;	msg[4] = offset;	return 5;}EXPORT_SYMBOL_GPL(spi_populate_sync_msg);int spi_populate_ppr_msg(unsigned char *msg, int period, int offset,		int width, int options){	msg[0] = EXTENDED_MESSAGE;	msg[1] = 6;	msg[2] = EXTENDED_PPR;	msg[3] = period;	msg[4] = 0;	msg[5] = offset;	msg[6] = width;	msg[7] = options;	return 8;}EXPORT_SYMBOL_GPL(spi_populate_ppr_msg);#ifdef CONFIG_SCSI_CONSTANTSstatic const char * const one_byte_msgs[] = {/* 0x00 */ "Task Complete", NULL /* Extended Message */, "Save Pointers",/* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", /* 0x06 */ "Abort Task Set", "Message Reject", "Nop", "Message Parity Error",/* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag",/* 0x0c */ "Target Reset", "Abort Task", "Clear Task Set", /* 0x0f */ "Initiate Recovery", "Release Recovery",/* 0x11 */ "Terminate Process", "Continue Task", "Target Transfer Disable",/* 0x14 */ NULL, NULL, "Clear ACA", "LUN Reset"};static const char * const two_byte_msgs[] = {/* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag",/* 0x23 */ "Ignore Wide Residue", "ACA"};static const char * const extended_msgs[] = {/* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request",/* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request",/* 0x04 */ "Parallel Protocol Request", "Modify Bidirectional Data Pointer"};static void print_nego(const unsigned char *msg, int per, int off, int width){	if (per) {		char buf[20];		period_to_str(buf, msg[per]);		printk("period = %s ns ", buf);	}	if (off)		printk("offset = %d ", msg[off]);	if (width)		printk("width = %d ", 8 << msg[width]);}static void print_ptr(const unsigned char *msg, int msb, const char *desc){	int ptr = (msg[msb] << 24) | (msg[msb+1] << 16) | (msg[msb+2] << 8) |			msg[msb+3];	printk("%s = %d ", desc, ptr);}int spi_print_msg(const unsigned char *msg){	int len = 1, i;	if (msg[0] == EXTENDED_MESSAGE) {		len = 2 + msg[1];		if (len == 2)			len += 256;		if (msg[2] < ARRAY_SIZE(extended_msgs))			printk ("%s ", extended_msgs[msg[2]]); 		else 			printk ("Extended Message, reserved code (0x%02x) ",				(int) msg[2]);		switch (msg[2]) {		case EXTENDED_MODIFY_DATA_POINTER:			print_ptr(msg, 3, "pointer");			break;		case EXTENDED_SDTR:			print_nego(msg, 3, 4, 0);			break;		case EXTENDED_WDTR:			print_nego(msg, 0, 0, 3);			break;		case EXTENDED_PPR:			print_nego(msg, 3, 5, 6);			break;		case EXTENDED_MODIFY_BIDI_DATA_PTR:			print_ptr(msg, 3, "out");			print_ptr(msg, 7, "in");			break;		default:		for (i = 2; i < len; ++i) 			printk("%02x ", msg[i]);		}	/* Identify */	} else if (msg[0] & 0x80) {		printk("Identify disconnect %sallowed %s %d ",			(msg[0] & 0x40) ? "" : "not ",			(msg[0] & 0x20) ? "target routine" : "lun",			msg[0] & 0x7);	/* Normal One byte */	} else if (msg[0] < 0x1f) {		if (msg[0] < ARRAY_SIZE(one_byte_msgs) && one_byte_msgs[msg[0]])			printk("%s ", one_byte_msgs[msg[0]]);		else			printk("reserved (%02x) ", msg[0]);	} else if (msg[0] == 0x55) {		printk("QAS Request ");	/* Two byte */	} else if (msg[0] <= 0x2f) {		if ((msg[0] - 0x20) < ARRAY_SIZE(two_byte_msgs))			printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], 				msg[1]);		else 			printk("reserved two byte (%02x %02x) ", 				msg[0], msg[1]);		len = 2;	} else 		printk("reserved ");	return len;}EXPORT_SYMBOL(spi_print_msg);#else  /* ifndef CONFIG_SCSI_CONSTANTS */int spi_print_msg(const unsigned char *msg){	int len = 1, i;	if (msg[0] == EXTENDED_MESSAGE) {		len = 2 + msg[1];		if (len == 2)			len += 256;		for (i = 0; i < len; ++i)			printk("%02x ", msg[i]);	/* Identify */	} else if (msg[0] & 0x80) {		printk("%02x ", msg[0]);	/* Normal One byte */	} else if ((msg[0] < 0x1f) || (msg[0] == 0x55)) {		printk("%02x ", msg[0]);	/* Two byte */	} else if (msg[0] <= 0x2f) {		printk("%02x %02x", msg[0], msg[1]);		len = 2;	} else 		printk("%02x ", msg[0]);	return len;}EXPORT_SYMBOL(spi_print_msg);#endif /* ! CONFIG_SCSI_CONSTANTS */#define SETUP_ATTRIBUTE(field)						\	i->private_attrs[count] = class_device_attr_##field;		\	if (!i->f->set_##field) {					\		i->private_attrs[count].attr.mode = S_IRUGO;		\		i->private_attrs[count].store = NULL;			\	}								\	i->attrs[count] = &i->private_attrs[count];			\	if (i->f->show_##field)						\		count++#define SETUP_RELATED_ATTRIBUTE(field, rel_field)			\	i->private_attrs[count] = class_device_attr_##field;		\	if (!i->f->set_##rel_field) {					\		i->private_attrs[count].attr.mode = S_IRUGO;		\		i->private_attrs[count].store = NULL;			\	}								\	i->attrs[count] = &i->private_attrs[count];			\	if (i->f->show_##rel_field)					\		count++#define SETUP_HOST_ATTRIBUTE(field)					\	i->private_host_attrs[count] = class_device_attr_##field;	\	if (!i->f->set_##field) {					\		i->private_host_attrs[count].attr.mode = S_IRUGO;	\		i->private_host_attrs[count].store = NULL;		\	}								\	i->host_attrs[count] = &i->private_host_attrs[count];		\	count++static int spi_device_match(struct attribute_container *cont,			    struct device *dev){	struct scsi_device *sdev;	struct Scsi_Host *shost;	struct spi_internal *i;	if (!scsi_is_sdev_device(dev))		return 0;	sdev = to_scsi_device(dev);	shost = sdev->host;	if (!shost->transportt  || shost->transportt->host_attrs.ac.class	    != &spi_host_class.class)		return 0;	/* Note: this class has no device attributes, so it has	 * no per-HBA allocation and thus we don't need to distinguish	 * the attribute containers for the device */	i = to_spi_internal(shost->transportt);	if (i->f->deny_binding && i->f->deny_binding(sdev->sdev_target))		return 0;	return 1;}static int spi_target_match(struct attribute_container *cont,			    struct device *dev){	struct Scsi_Host *shost;	struct scsi_target *starget;	struct spi_internal *i;	if (!scsi_is_target_device(dev))		return 0;	shost = dev_to_shost(dev->parent);	if (!shost->transportt  || shost->transportt->host_attrs.ac.class	    != &spi_host_class.class)		return 0;	i = to_spi_internal(shost->transportt);	starget = to_scsi_target(dev);	if (i->f->deny_binding && i->f->deny_binding(starget))		return 0;	return &i->t.target_attrs.ac == cont;}static DECLARE_TRANSPORT_CLASS(spi_transport_class,			       "spi_transport",			       spi_setup_transport_attrs,			       NULL,			       NULL);static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,				    spi_device_match,				    spi_device_configure);struct scsi_transport_template *spi_attach_transport(struct spi_function_template *ft){	int count = 0;	struct spi_internal *i = kzalloc(sizeof(struct spi_internal),					 GFP_KERNEL);	if (unlikely(!i))		return NULL;	i->t.target_attrs.ac.class = &spi_transport_class.class;	i->t.target_attrs.ac.attrs = &i->attrs[0];	i->t.target_attrs.ac.match = spi_target_match;	transport_container_register(&i->t.target_attrs);	i->t.target_size = sizeof(struct spi_transport_attrs);	i->t.host_attrs.ac.class = &spi_host_class.class;	i->t.host_attrs.ac.attrs = &i->host_attrs[0];	i->t.host_attrs.ac.match = spi_host_match;	transport_container_register(&i->t.host_attrs);	i->t.host_size = sizeof(struct spi_host_attrs);	i->f = ft;	SETUP_ATTRIBUTE(period);	SETUP_RELATED_ATTRIBUTE(min_period, period);	SETUP_ATTRIBUTE(offset);	SETUP_RELATED_ATTRIBUTE(max_offset, offset);	SETUP_ATTRIBUTE(width);	SETUP_RELATED_ATTRIBUTE(max_width, width);	SETUP_ATTRIBUTE(iu);	SETUP_ATTRIBUTE(dt);	SETUP_ATTRIBUTE(qas);	SETUP_ATTRIBUTE(wr_flow);	SETUP_ATTRIBUTE(rd_strm);	SETUP_ATTRIBUTE(rti);	SETUP_ATTRIBUTE(pcomp_en);	SETUP_ATTRIBUTE(hold_mcs);	/* if you add an attribute but forget to increase SPI_NUM_ATTRS	 * this bug will trigger */	BUG_ON(count > SPI_NUM_ATTRS);	i->attrs[count++] = &class_device_attr_revalidate;	i->attrs[count] = NULL;	count = 0;	SETUP_HOST_ATTRIBUTE(signalling);	BUG_ON(count > SPI_HOST_ATTRS);	i->host_attrs[count] = NULL;	return &i->t;}EXPORT_SYMBOL(spi_attach_transport);void spi_release_transport(struct scsi_transport_template *t){	struct spi_internal *i = to_spi_internal(t);	transport_container_unregister(&i->t.target_attrs);	transport_container_unregister(&i->t.host_attrs);	kfree(i);}EXPORT_SYMBOL(spi_release_transport);static __init int spi_transport_init(void){	int error = transport_class_register(&spi_transport_class);	if (error)		return error;	error = anon_transport_class_register(&spi_device_class);	return transport_class_register(&spi_host_class);}static void __exit spi_transport_exit(void){	transport_class_unregister(&spi_transport_class);	anon_transport_class_unregister(&spi_device_class);	transport_class_unregister(&spi_host_class);}MODULE_AUTHOR("Martin Hicks");MODULE_DESCRIPTION("SPI Transport Attributes");MODULE_LICENSE("GPL");module_init(spi_transport_init);module_exit(spi_transport_exit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?