diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_spi.c')
-rw-r--r-- | drivers/scsi/scsi_transport_spi.c | 136 |
1 files changed, 132 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 38a53b5f9e9a..46da6fe10ad5 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | #include <linux/config.h> | ||
21 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
22 | #include <linux/init.h> | 23 | #include <linux/init.h> |
23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
@@ -378,9 +379,7 @@ static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); | |||
378 | 379 | ||
379 | /* Translate the period into ns according to the current spec | 380 | /* Translate the period into ns according to the current spec |
380 | * for SDTR/PPR messages */ | 381 | * for SDTR/PPR messages */ |
381 | static ssize_t | 382 | static int period_to_str(char *buf, int period) |
382 | show_spi_transport_period_helper(struct class_device *cdev, char *buf, | ||
383 | int period) | ||
384 | { | 383 | { |
385 | int len, picosec; | 384 | int len, picosec; |
386 | 385 | ||
@@ -398,6 +397,14 @@ show_spi_transport_period_helper(struct class_device *cdev, char *buf, | |||
398 | len = sprint_frac(buf, picosec, 1000); | 397 | len = sprint_frac(buf, picosec, 1000); |
399 | } | 398 | } |
400 | 399 | ||
400 | return len; | ||
401 | } | ||
402 | |||
403 | static ssize_t | ||
404 | show_spi_transport_period_helper(struct class_device *cdev, char *buf, | ||
405 | int period) | ||
406 | { | ||
407 | int len = period_to_str(buf, period); | ||
401 | buf[len++] = '\n'; | 408 | buf[len++] = '\n'; |
402 | buf[len] = '\0'; | 409 | buf[len] = '\0'; |
403 | return len; | 410 | return len; |
@@ -1041,12 +1048,133 @@ void spi_display_xfer_agreement(struct scsi_target *starget) | |||
1041 | tp->hold_mcs ? " HMCS" : "", | 1048 | tp->hold_mcs ? " HMCS" : "", |
1042 | tmp, tp->offset); | 1049 | tmp, tp->offset); |
1043 | } else { | 1050 | } else { |
1044 | dev_info(&starget->dev, "%sasynchronous.\n", | 1051 | dev_info(&starget->dev, "%sasynchronous\n", |
1045 | tp->width ? "wide " : ""); | 1052 | tp->width ? "wide " : ""); |
1046 | } | 1053 | } |
1047 | } | 1054 | } |
1048 | EXPORT_SYMBOL(spi_display_xfer_agreement); | 1055 | EXPORT_SYMBOL(spi_display_xfer_agreement); |
1049 | 1056 | ||
1057 | #ifdef CONFIG_SCSI_CONSTANTS | ||
1058 | static const char * const one_byte_msgs[] = { | ||
1059 | /* 0x00 */ "Command Complete", NULL, "Save Pointers", | ||
1060 | /* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", | ||
1061 | /* 0x06 */ "Abort", "Message Reject", "Nop", "Message Parity Error", | ||
1062 | /* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag", | ||
1063 | /* 0x0c */ "Bus device reset", "Abort Tag", "Clear Queue", | ||
1064 | /* 0x0f */ "Initiate Recovery", "Release Recovery" | ||
1065 | }; | ||
1066 | |||
1067 | static const char * const two_byte_msgs[] = { | ||
1068 | /* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag", | ||
1069 | /* 0x23 */ "Ignore Wide Residue" | ||
1070 | }; | ||
1071 | |||
1072 | static const char * const extended_msgs[] = { | ||
1073 | /* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request", | ||
1074 | /* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request", | ||
1075 | /* 0x04 */ "Parallel Protocol Request" | ||
1076 | }; | ||
1077 | |||
1078 | void print_nego(const unsigned char *msg, int per, int off, int width) | ||
1079 | { | ||
1080 | if (per) { | ||
1081 | char buf[20]; | ||
1082 | period_to_str(buf, msg[per]); | ||
1083 | printk("period = %s ns ", buf); | ||
1084 | } | ||
1085 | |||
1086 | if (off) | ||
1087 | printk("offset = %d ", msg[off]); | ||
1088 | if (width) | ||
1089 | printk("width = %d ", 8 << msg[width]); | ||
1090 | } | ||
1091 | |||
1092 | int spi_print_msg(const unsigned char *msg) | ||
1093 | { | ||
1094 | int len = 0, i; | ||
1095 | if (msg[0] == EXTENDED_MESSAGE) { | ||
1096 | len = 3 + msg[1]; | ||
1097 | if (msg[2] < ARRAY_SIZE(extended_msgs)) | ||
1098 | printk ("%s ", extended_msgs[msg[2]]); | ||
1099 | else | ||
1100 | printk ("Extended Message, reserved code (0x%02x) ", | ||
1101 | (int) msg[2]); | ||
1102 | switch (msg[2]) { | ||
1103 | case EXTENDED_MODIFY_DATA_POINTER: | ||
1104 | printk("pointer = %d", (int) (msg[3] << 24) | | ||
1105 | (msg[4] << 16) | (msg[5] << 8) | msg[6]); | ||
1106 | break; | ||
1107 | case EXTENDED_SDTR: | ||
1108 | print_nego(msg, 3, 4, 0); | ||
1109 | break; | ||
1110 | case EXTENDED_WDTR: | ||
1111 | print_nego(msg, 0, 0, 3); | ||
1112 | break; | ||
1113 | case EXTENDED_PPR: | ||
1114 | print_nego(msg, 3, 5, 6); | ||
1115 | break; | ||
1116 | default: | ||
1117 | for (i = 2; i < len; ++i) | ||
1118 | printk("%02x ", msg[i]); | ||
1119 | } | ||
1120 | /* Identify */ | ||
1121 | } else if (msg[0] & 0x80) { | ||
1122 | printk("Identify disconnect %sallowed %s %d ", | ||
1123 | (msg[0] & 0x40) ? "" : "not ", | ||
1124 | (msg[0] & 0x20) ? "target routine" : "lun", | ||
1125 | msg[0] & 0x7); | ||
1126 | len = 1; | ||
1127 | /* Normal One byte */ | ||
1128 | } else if (msg[0] < 0x1f) { | ||
1129 | if (msg[0] < ARRAY_SIZE(one_byte_msgs)) | ||
1130 | printk(one_byte_msgs[msg[0]]); | ||
1131 | else | ||
1132 | printk("reserved (%02x) ", msg[0]); | ||
1133 | len = 1; | ||
1134 | /* Two byte */ | ||
1135 | } else if (msg[0] <= 0x2f) { | ||
1136 | if ((msg[0] - 0x20) < ARRAY_SIZE(two_byte_msgs)) | ||
1137 | printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], | ||
1138 | msg[1]); | ||
1139 | else | ||
1140 | printk("reserved two byte (%02x %02x) ", | ||
1141 | msg[0], msg[1]); | ||
1142 | len = 2; | ||
1143 | } else | ||
1144 | printk("reserved"); | ||
1145 | return len; | ||
1146 | } | ||
1147 | EXPORT_SYMBOL(spi_print_msg); | ||
1148 | |||
1149 | #else /* ifndef CONFIG_SCSI_CONSTANTS */ | ||
1150 | |||
1151 | int spi_print_msg(const unsigned char *msg) | ||
1152 | { | ||
1153 | int len = 0, i; | ||
1154 | |||
1155 | if (msg[0] == EXTENDED_MESSAGE) { | ||
1156 | len = 3 + msg[1]; | ||
1157 | for (i = 0; i < len; ++i) | ||
1158 | printk("%02x ", msg[i]); | ||
1159 | /* Identify */ | ||
1160 | } else if (msg[0] & 0x80) { | ||
1161 | printk("%02x ", msg[0]); | ||
1162 | len = 1; | ||
1163 | /* Normal One byte */ | ||
1164 | } else if (msg[0] < 0x1f) { | ||
1165 | printk("%02x ", msg[0]); | ||
1166 | len = 1; | ||
1167 | /* Two byte */ | ||
1168 | } else if (msg[0] <= 0x2f) { | ||
1169 | printk("%02x %02x", msg[0], msg[1]); | ||
1170 | len = 2; | ||
1171 | } else | ||
1172 | printk("%02x ", msg[0]); | ||
1173 | return len; | ||
1174 | } | ||
1175 | EXPORT_SYMBOL(spi_print_msg); | ||
1176 | #endif /* ! CONFIG_SCSI_CONSTANTS */ | ||
1177 | |||
1050 | #define SETUP_ATTRIBUTE(field) \ | 1178 | #define SETUP_ATTRIBUTE(field) \ |
1051 | i->private_attrs[count] = class_device_attr_##field; \ | 1179 | i->private_attrs[count] = class_device_attr_##field; \ |
1052 | if (!i->f->set_##field) { \ | 1180 | if (!i->f->set_##field) { \ |