#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <scsi/scsi.h>
#include "scsi_priv.h"
#include <scsi/scsi_device.h>
/* Private data accessors (keep these out of the header file) */
#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
-#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
+#define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
+#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
struct spi_internal {
struct scsi_transport_template t;
{
int i;
- for (i = 0; i < sizeof(signal_types)/sizeof(signal_types[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(signal_types); i++) {
if (type == signal_types[i].value)
return signal_types[i].name;
}
{
int i, len;
- for (i = 0; i < sizeof(signal_types)/sizeof(signal_types[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(signal_types); i++) {
len = strlen(signal_types[i].name);
if (strncmp(name, signal_types[i].name, len) == 0 &&
(name[len] == '\n' || name[len] == '\0'))
spi_pcomp_en(starget) = 0;
spi_hold_mcs(starget) = 0;
spi_dv_pending(starget) = 0;
+ spi_dv_in_progress(starget) = 0;
spi_initial_dv(starget) = 0;
- init_MUTEX(&spi_dv_sem(starget));
+ mutex_init(&spi_dv_mutex(starget));
return 0;
}
/* Translate the period into ns according to the current spec
* for SDTR/PPR messages */
-static ssize_t
-show_spi_transport_period_helper(struct class_device *cdev, char *buf,
- int period)
+static int period_to_str(char *buf, int period)
{
int len, picosec;
len = sprint_frac(buf, picosec, 1000);
}
+ return len;
+}
+
+static ssize_t
+show_spi_transport_period_helper(char *buf, int period)
+{
+ int len = period_to_str(buf, period);
buf[len++] = '\n';
buf[len] = '\0';
return len;
if (i->f->get_period)
i->f->get_period(starget);
- return show_spi_transport_period_helper(cdev, buf, tp->period);
+ return show_spi_transport_period_helper(buf, tp->period);
}
static ssize_t
struct spi_transport_attrs *tp =
(struct spi_transport_attrs *)&starget->starget_data;
- return show_spi_transport_period_helper(cdev, buf, tp->min_period);
+ return show_spi_transport_period_helper(buf, tp->min_period);
}
static ssize_t
{
struct spi_internal *i = to_spi_internal(sdev->host->transportt);
struct scsi_target *starget = sdev->sdev_target;
+ struct Scsi_Host *shost = sdev->host;
int len = sdev->inquiry_len;
/* first set us up for narrow async */
DV_SET(offset, 0);
DV_SET(period, spi_min_period(starget));
/* try QAS requests; this should be harmless to set if the
* target supports it */
- if (scsi_device_qas(sdev))
+ if (scsi_device_qas(sdev)) {
DV_SET(qas, 1);
- /* Also try IU transfers */
- if (scsi_device_ius(sdev))
+ } else {
+ DV_SET(qas, 0);
+ }
+
+ if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+ /* This u320 (or u640). Set IU transfers */
DV_SET(iu, 1);
- if (spi_min_period(starget) < 9) {
- /* This u320 (or u640). Ignore the coupled parameters
- * like DT and IU, but set the optional ones */
+ /* Then set the optional parameters */
DV_SET(rd_strm, 1);
DV_SET(wr_flow, 1);
DV_SET(rti, 1);
if (spi_min_period(starget) == 8)
DV_SET(pcomp_en, 1);
+ } else {
+ DV_SET(iu, 0);
+ }
+
+ /* now that we've done all this, actually check the bus
+ * signal type (if known). Some devices are stupid on
+ * a SE bus and still claim they can try LVD only settings */
+ if (i->f->get_signalling)
+ i->f->get_signalling(shost);
+ if (spi_signalling(shost) == SPI_SIGNAL_SE ||
+ spi_signalling(shost) == SPI_SIGNAL_HVD ||
+ !scsi_device_dt(sdev)) {
+ DV_SET(dt, 0);
+ } else {
+ DV_SET(dt, 1);
}
/* Do the read only INQUIRY tests */
spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
if (unlikely(scsi_device_get(sdev)))
return;
- buffer = kmalloc(len, GFP_KERNEL);
+ if (unlikely(spi_dv_in_progress(starget)))
+ return;
+ spi_dv_in_progress(starget) = 1;
+
+ buffer = kzalloc(len, GFP_KERNEL);
if (unlikely(!buffer))
goto out_put;
- memset(buffer, 0, len);
-
/* We need to verify that the actual device will quiesce; the
* later target quiesce is just a nice to have */
if (unlikely(scsi_device_quiesce(sdev)))
scsi_target_quiesce(starget);
spi_dv_pending(starget) = 1;
- down(&spi_dv_sem(starget));
+ mutex_lock(&spi_dv_mutex(starget));
starget_printk(KERN_INFO, starget, "Beginning Domain Validation\n");
starget_printk(KERN_INFO, starget, "Ending Domain Validation\n");
- up(&spi_dv_sem(starget));
+ mutex_unlock(&spi_dv_mutex(starget));
spi_dv_pending(starget) = 0;
scsi_target_resume(starget);
out_free:
kfree(buffer);
out_put:
+ spi_dv_in_progress(starget) = 0;
scsi_device_put(sdev);
}
EXPORT_SYMBOL(spi_dv_device);
};
static void
-spi_dv_device_work_wrapper(void *data)
+spi_dv_device_work_wrapper(struct work_struct *work)
{
- struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+ struct work_queue_wrapper *wqw =
+ container_of(work, struct work_queue_wrapper, work);
struct scsi_device *sdev = wqw->sdev;
kfree(wqw);
return;
}
- INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw);
+ INIT_WORK(&wqw->work, spi_dv_device_work_wrapper);
wqw->sdev = sdev;
schedule_work(&wqw->work);
tp->hold_mcs ? " HMCS" : "",
tmp, tp->offset);
} else {
- dev_info(&starget->dev, "%sasynchronous.\n",
+ 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_CONSTANTS
+static 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) { \
struct scsi_transport_template *
spi_attach_transport(struct spi_function_template *ft)
{
- struct spi_internal *i = kmalloc(sizeof(struct spi_internal),
- GFP_KERNEL);
int count = 0;
+ struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
+ GFP_KERNEL);
+
if (unlikely(!i))
return NULL;
- memset(i, 0, sizeof(struct spi_internal));
-
-
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;