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 + -
显示快捷键?