Skip to content

Commit

Permalink
[SCSI] implement parameter limits in the SPI transport class
Browse files Browse the repository at this point in the history
There's a basic need not to have parameters go under or over certain
values when doing domain validation.  The basic ones are

max_offset, max_width and min_period

This patch makes the transport class take and enforce these three
limits.  Currently they can be set by the user, although they could
obviously be read from the HBA's on-board NVRAM area during
slave_configure (if it has one).

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
James Bottomley authored and James Bottomley committed May 20, 2005
1 parent 88d7bd8 commit 62a8612
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 27 deletions.
188 changes: 161 additions & 27 deletions drivers/scsi/scsi_transport_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

#define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a)

#define SPI_NUM_ATTRS 10 /* increase this if you add attributes */
#define SPI_NUM_ATTRS 13 /* increase this if you add attributes */
#define SPI_OTHER_ATTRS 1 /* Increase this if you add "always
* on" attributes */
#define SPI_HOST_ATTRS 1
Expand Down Expand Up @@ -219,8 +219,11 @@ static int spi_setup_transport_attrs(struct device *dev)
struct scsi_target *starget = to_scsi_target(dev);

spi_period(starget) = -1; /* illegal value */
spi_min_period(starget) = 0;
spi_offset(starget) = 0; /* async */
spi_max_offset(starget) = 255;
spi_width(starget) = 0; /* narrow */
spi_max_width(starget) = 1;
spi_iu(starget) = 0; /* no IU */
spi_dt(starget) = 0; /* ST */
spi_qas(starget) = 0;
Expand All @@ -235,6 +238,34 @@ static int spi_setup_transport_attrs(struct device *dev)
return 0;
}

#define spi_transport_show_simple(field, format_string) \
\
static ssize_t \
show_spi_transport_##field(struct class_device *cdev, char *buf) \
{ \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct spi_transport_attrs *tp; \
\
tp = (struct spi_transport_attrs *)&starget->starget_data; \
return snprintf(buf, 20, format_string, tp->field); \
}

#define spi_transport_store_simple(field, format_string) \
\
static ssize_t \
store_spi_transport_##field(struct class_device *cdev, const char *buf, \
size_t count) \
{ \
int val; \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct spi_transport_attrs *tp; \
\
tp = (struct spi_transport_attrs *)&starget->starget_data; \
val = simple_strtoul(buf, NULL, 0); \
tp->field = val; \
return count; \
}

#define spi_transport_show_function(field, format_string) \
\
static ssize_t \
Expand All @@ -261,6 +292,25 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
struct spi_internal *i = to_spi_internal(shost->transportt); \
\
val = simple_strtoul(buf, NULL, 0); \
i->f->set_##field(starget, val); \
return count; \
}

#define spi_transport_store_max(field, format_string) \
static ssize_t \
store_spi_transport_##field(struct class_device *cdev, const char *buf, \
size_t count) \
{ \
int val; \
struct scsi_target *starget = transport_class_to_starget(cdev); \
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
struct spi_internal *i = to_spi_internal(shost->transportt); \
struct spi_transport_attrs *tp \
= (struct spi_transport_attrs *)&starget->starget_data; \
\
val = simple_strtoul(buf, NULL, 0); \
if (val > tp->max_##field) \
val = tp->max_##field; \
i->f->set_##field(starget, val); \
return count; \
}
Expand All @@ -272,9 +322,24 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
show_spi_transport_##field, \
store_spi_transport_##field);

#define spi_transport_simple_attr(field, format_string) \
spi_transport_show_simple(field, format_string) \
spi_transport_store_simple(field, format_string) \
static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
show_spi_transport_##field, \
store_spi_transport_##field);

#define spi_transport_max_attr(field, format_string) \
spi_transport_show_function(field, format_string) \
spi_transport_store_max(field, format_string) \
spi_transport_simple_attr(max_##field, format_string) \
static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
show_spi_transport_##field, \
store_spi_transport_##field);

/* The Parallel SCSI Tranport Attributes: */
spi_transport_rd_attr(offset, "%d\n");
spi_transport_rd_attr(width, "%d\n");
spi_transport_max_attr(offset, "%d\n");
spi_transport_max_attr(width, "%d\n");
spi_transport_rd_attr(iu, "%d\n");
spi_transport_rd_attr(dt, "%d\n");
spi_transport_rd_attr(qas, "%d\n");
Expand All @@ -300,26 +365,18 @@ static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate);

/* Translate the period into ns according to the current spec
* for SDTR/PPR messages */
static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf)

static ssize_t
show_spi_transport_period_helper(struct class_device *cdev, char *buf,
int period)
{
struct scsi_target *starget = transport_class_to_starget(cdev);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
struct spi_transport_attrs *tp;
int len, picosec;
struct spi_internal *i = to_spi_internal(shost->transportt);

tp = (struct spi_transport_attrs *)&starget->starget_data;

if (i->f->get_period)
i->f->get_period(starget);

if (tp->period < 0 || tp->period > 0xff) {
if (period < 0 || period > 0xff) {
picosec = -1;
} else if (tp->period <= SPI_STATIC_PPR) {
picosec = ppr_to_ps[tp->period];
} else if (period <= SPI_STATIC_PPR) {
picosec = ppr_to_ps[period];
} else {
picosec = tp->period * 4000;
picosec = period * 4000;
}

if (picosec == -1) {
Expand All @@ -334,12 +391,9 @@ static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf)
}

static ssize_t
store_spi_transport_period(struct class_device *cdev, const char *buf,
size_t count)
store_spi_transport_period_helper(struct class_device *cdev, const char *buf,
size_t count, int *periodp)
{
struct scsi_target *starget = transport_class_to_starget(cdev);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
struct spi_internal *i = to_spi_internal(shost->transportt);
int j, picosec, period = -1;
char *endp;

Expand Down Expand Up @@ -368,15 +422,79 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
if (period > 0xff)
period = 0xff;

i->f->set_period(starget, period);
*periodp = period;

return count;
}

static ssize_t
show_spi_transport_period(struct class_device *cdev, char *buf)
{
struct scsi_target *starget = transport_class_to_starget(cdev);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
struct spi_internal *i = to_spi_internal(shost->transportt);
struct spi_transport_attrs *tp =
(struct spi_transport_attrs *)&starget->starget_data;

if (i->f->get_period)
i->f->get_period(starget);

return show_spi_transport_period_helper(cdev, buf, tp->period);
}

static ssize_t
store_spi_transport_period(struct class_device *cdev, const char *buf,
size_t count)
{
struct scsi_target *starget = transport_class_to_starget(cdev);
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
struct spi_internal *i = to_spi_internal(shost->transportt);
struct spi_transport_attrs *tp =
(struct spi_transport_attrs *)&starget->starget_data;
int period, retval;

retval = store_spi_transport_period_helper(cdev, buf, count, &period);

if (period < tp->min_period)
period = tp->min_period;

i->f->set_period(starget, period);

return retval;
}

static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR,
show_spi_transport_period,
store_spi_transport_period);

static ssize_t
show_spi_transport_min_period(struct class_device *cdev, char *buf)
{
struct scsi_target *starget = transport_class_to_starget(cdev);
struct spi_transport_attrs *tp =
(struct spi_transport_attrs *)&starget->starget_data;

return show_spi_transport_period_helper(cdev, buf, tp->min_period);
}

static ssize_t
store_spi_transport_min_period(struct class_device *cdev, const char *buf,
size_t count)
{
struct scsi_target *starget = transport_class_to_starget(cdev);
struct spi_transport_attrs *tp =
(struct spi_transport_attrs *)&starget->starget_data;

return store_spi_transport_period_helper(cdev, buf, count,
&tp->min_period);
}


static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR,
show_spi_transport_min_period,
store_spi_transport_min_period);


static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf)
{
struct Scsi_Host *shost = transport_class_to_shost(cdev);
Expand Down Expand Up @@ -642,6 +760,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
{
struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
struct scsi_device *sdev = sreq->sr_device;
struct scsi_target *starget = sdev->sdev_target;
int len = sdev->inquiry_len;
/* first set us up for narrow async */
DV_SET(offset, 0);
Expand All @@ -655,9 +774,11 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
}

/* test width */
if (i->f->set_width && sdev->wdtr) {
if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) {
i->f->set_width(sdev->sdev_target, 1);

printk("WIDTH IS %d\n", spi_max_width(starget));

if (spi_dv_device_compare_inquiry(sreq, buffer,
buffer + len,
DV_LOOPS)
Expand All @@ -684,8 +805,8 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
retry:

/* now set up to the maximum */
DV_SET(offset, 255);
DV_SET(period, 1);
DV_SET(offset, spi_max_offset(starget));
DV_SET(period, spi_min_period(starget));

if (len == 0) {
SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n");
Expand Down Expand Up @@ -892,6 +1013,16 @@ EXPORT_SYMBOL(spi_display_xfer_agreement);
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) { \
Expand Down Expand Up @@ -975,8 +1106,11 @@ spi_attach_transport(struct spi_function_template *ft)
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);
Expand Down
6 changes: 6 additions & 0 deletions include/scsi/scsi_transport_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ struct scsi_transport_template;

struct spi_transport_attrs {
int period; /* value in the PPR/SDTR command */
int min_period;
int offset;
int max_offset;
unsigned int width:1; /* 0 - narrow, 1 - wide */
unsigned int max_width:1;
unsigned int iu:1; /* Information Units enabled */
unsigned int dt:1; /* DT clocking enabled */
unsigned int qas:1; /* Quick Arbitration and Selection enabled */
Expand Down Expand Up @@ -63,8 +66,11 @@ struct spi_host_attrs {

/* accessor functions */
#define spi_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->period)
#define spi_min_period(x) (((struct spi_transport_attrs *)&(x)->starget_data)->min_period)
#define spi_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->offset)
#define spi_max_offset(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_offset)
#define spi_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->width)
#define spi_max_width(x) (((struct spi_transport_attrs *)&(x)->starget_data)->max_width)
#define spi_iu(x) (((struct spi_transport_attrs *)&(x)->starget_data)->iu)
#define spi_dt(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dt)
#define spi_qas(x) (((struct spi_transport_attrs *)&(x)->starget_data)->qas)
Expand Down

0 comments on commit 62a8612

Please sign in to comment.