Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 35036
b: refs/heads/master
c: 0f29b96
h: refs/heads/master
v: v3
  • Loading branch information
James Smart authored and James Bottomley committed Sep 5, 2006
1 parent 1023d2c commit 5e0ff33
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ae36764a230ff6a278ed93735acf5fcda08f2786
refs/heads/master: 0f29b966d60e9a4f5ecff9f3832257b38aea4f13
134 changes: 123 additions & 11 deletions trunk/drivers/scsi/scsi_transport_fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,15 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)


static void fc_timeout_deleted_rport(void *data);
static void fc_timeout_fail_rport_io(void *data);
static void fc_scsi_scan_rport(void *data);

/*
* Attribute counts pre object type...
* Increase these values if you add attributes
*/
#define FC_STARGET_NUM_ATTRS 3
#define FC_RPORT_NUM_ATTRS 9
#define FC_RPORT_NUM_ATTRS 10
#define FC_HOST_NUM_ATTRS 17

struct fc_internal {
Expand Down Expand Up @@ -622,11 +623,14 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \
struct fc_rport *rport = transport_class_to_rport(cdev); \
struct Scsi_Host *shost = rport_to_shost(rport); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
char *cp; \
if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
(rport->port_state == FC_PORTSTATE_DELETED) || \
(rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
return -EBUSY; \
val = simple_strtoul(buf, NULL, 0); \
val = simple_strtoul(buf, &cp, 0); \
if (*cp && (*cp != '\n')) \
return -EINVAL; \
i->f->set_rport_##field(rport, val); \
return count; \
}
Expand Down Expand Up @@ -708,6 +712,13 @@ static FC_CLASS_DEVICE_ATTR(rport, title, S_IRUGO, \
if (i->f->show_rport_##field) \
count++

#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \
{ \
i->private_rport_attrs[count] = class_device_attr_rport_##field; \
i->rport_attrs[count] = &i->private_rport_attrs[count]; \
count++; \
}


/* The FC Transport Remote Port Attributes: */

Expand Down Expand Up @@ -740,12 +751,14 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf,
struct fc_rport *rport = transport_class_to_rport(cdev);
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
char *cp;
if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
(rport->port_state == FC_PORTSTATE_DELETED) ||
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
return -EBUSY;
val = simple_strtoul(buf, NULL, 0);
if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
val = simple_strtoul(buf, &cp, 0);
if ((*cp && (*cp != '\n')) ||
(val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
return -EINVAL;
i->f->set_rport_dev_loss_tmo(rport, val);
return count;
Expand Down Expand Up @@ -795,6 +808,44 @@ static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20);

/*
* fast_io_fail_tmo attribute
*/
static ssize_t
show_fc_rport_fast_io_fail_tmo (struct class_device *cdev, char *buf)
{
struct fc_rport *rport = transport_class_to_rport(cdev);

if (rport->fast_io_fail_tmo == -1)
return snprintf(buf, 5, "off\n");
return snprintf(buf, 20, "%d\n", rport->fast_io_fail_tmo);
}

static ssize_t
store_fc_rport_fast_io_fail_tmo(struct class_device *cdev, const char *buf,
size_t count)
{
int val;
char *cp;
struct fc_rport *rport = transport_class_to_rport(cdev);

if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
(rport->port_state == FC_PORTSTATE_DELETED) ||
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
return -EBUSY;
if (strncmp(buf, "off", 3) == 0)
rport->fast_io_fail_tmo = -1;
else {
val = simple_strtoul(buf, &cp, 0);
if ((*cp && (*cp != '\n')) ||
(val < 0) || (val >= rport->dev_loss_tmo))
return -EINVAL;
rport->fast_io_fail_tmo = val;
}
return count;
}
static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo);


/*
Expand Down Expand Up @@ -880,8 +931,11 @@ store_fc_host_##field(struct class_device *cdev, const char *buf, \
int val; \
struct Scsi_Host *shost = transport_class_to_shost(cdev); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
char *cp; \
\
val = simple_strtoul(buf, NULL, 0); \
val = simple_strtoul(buf, &cp, 0); \
if (*cp && (*cp != '\n')) \
return -EINVAL; \
i->f->set_host_##field(shost, val); \
return count; \
}
Expand Down Expand Up @@ -1481,6 +1535,8 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
if (ft->terminate_rport_io)
SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo);

BUG_ON(count > FC_RPORT_NUM_ATTRS);

Expand Down Expand Up @@ -1552,7 +1608,7 @@ fc_flush_work(struct Scsi_Host *shost)
* @delay: jiffies to delay the work queuing
*
* Return value:
* 0 on success / != 0 for error
* 1 on success / 0 already queued / < 0 for error
**/
static int
fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
Expand All @@ -1567,6 +1623,9 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
return -EINVAL;
}

if (delay == 0)
return queue_work(fc_host_devloss_work_q(shost), work);

return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay);
}

Expand Down Expand Up @@ -1659,10 +1718,23 @@ fc_starget_delete(void *data)
struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport);
unsigned long flags;
struct fc_internal *i = to_fc_internal(shost->transportt);

/*
* Involve the LLDD if possible. All io on the rport is to
* be terminated, either as part of the dev_loss_tmo callback
* processing, or via the terminate_rport_io function.
*/
if (i->f->dev_loss_tmo_callbk)
i->f->dev_loss_tmo_callbk(rport);
else if (i->f->terminate_rport_io)
i->f->terminate_rport_io(rport);

spin_lock_irqsave(shost->host_lock, flags);
if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
spin_unlock_irqrestore(shost->host_lock, flags);
if (!cancel_delayed_work(&rport->fail_io_work))
fc_flush_devloss(shost);
if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);
spin_lock_irqsave(shost->host_lock, flags);
Expand All @@ -1685,10 +1757,7 @@ fc_rport_final_delete(void *data)
struct fc_rport *rport = (struct fc_rport *)data;
struct device *dev = &rport->dev;
struct Scsi_Host *shost = rport_to_shost(rport);

/* Delete SCSI target and sdevs */
if (rport->scsi_target_id != -1)
fc_starget_delete(data);
struct fc_internal *i = to_fc_internal(shost->transportt);

/*
* if a scan is pending, flush the SCSI Host work_q so that
Expand All @@ -1697,6 +1766,14 @@ fc_rport_final_delete(void *data)
if (rport->flags & FC_RPORT_SCAN_PENDING)
scsi_flush_work(shost);

/* Delete SCSI target and sdevs */
if (rport->scsi_target_id != -1)
fc_starget_delete(data);
else if (i->f->dev_loss_tmo_callbk)
i->f->dev_loss_tmo_callbk(rport);
else if (i->f->terminate_rport_io)
i->f->terminate_rport_io(rport);

transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
Expand Down Expand Up @@ -1748,8 +1825,10 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
if (fci->f->dd_fcrport_size)
rport->dd_data = &rport[1];
rport->channel = channel;
rport->fast_io_fail_tmo = -1;

INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport);
INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport);
INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport);
INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport);
Expand Down Expand Up @@ -1913,11 +1992,13 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
/* restart the target */

/*
* Stop the target timer first. Take no action
* Stop the target timers first. Take no action
* on the del_timer failure as the state
* machine state change will validate the
* transaction.
*/
if (!cancel_delayed_work(&rport->fail_io_work))
fc_flush_devloss(shost);
if (!cancel_delayed_work(work))
fc_flush_devloss(shost);

Expand Down Expand Up @@ -2061,6 +2142,7 @@ void
fc_remote_port_delete(struct fc_rport *rport)
{
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
int timeout = rport->dev_loss_tmo;
unsigned long flags;

Expand Down Expand Up @@ -2091,6 +2173,12 @@ fc_remote_port_delete(struct fc_rport *rport)

scsi_target_block(&rport->dev);

/* see if we need to kill io faster than waiting for device loss */
if ((rport->fast_io_fail_tmo != -1) &&
(rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io))
fc_queue_devloss_work(shost, &rport->fail_io_work,
rport->fast_io_fail_tmo * HZ);

/* cap the length the devices can be blocked until they are deleted */
fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ);
}
Expand Down Expand Up @@ -2150,6 +2238,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
* machine state change will validate the
* transaction.
*/
if (!cancel_delayed_work(&rport->fail_io_work))
fc_flush_devloss(shost);
if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);

Expand Down Expand Up @@ -2270,6 +2360,28 @@ fc_timeout_deleted_rport(void *data)
fc_queue_work(shost, &rport->stgt_delete_work);
}

/**
* fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
* disconnected SCSI target.
*
* @data: rport to terminate io on.
*
* Notes: Only requests the failure of the io, not that all are flushed
* prior to returning.
**/
static void
fc_timeout_fail_rport_io(void *data)
{
struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);

if (rport->port_state != FC_PORTSTATE_BLOCKED)
return;

i->f->terminate_rport_io(rport);
}

/**
* fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
*
Expand Down
5 changes: 5 additions & 0 deletions trunk/include/scsi/scsi_transport_fc.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ struct fc_rport { /* aka fc_starget_attrs */
u32 roles;
enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */
u32 scsi_target_id;
u32 fast_io_fail_tmo;

/* exported data */
void *dd_data; /* Used for driver-specific storage */
Expand All @@ -207,6 +208,7 @@ struct fc_rport { /* aka fc_starget_attrs */
struct device dev;
struct work_struct dev_loss_work;
struct work_struct scan_work;
struct work_struct fail_io_work;
struct work_struct stgt_delete_work;
struct work_struct rport_delete_work;
} __attribute__((aligned(sizeof(unsigned long))));
Expand Down Expand Up @@ -445,6 +447,9 @@ struct fc_function_template {

int (*issue_fc_host_lip)(struct Scsi_Host *);

void (*dev_loss_tmo_callbk)(struct fc_rport *);
void (*terminate_rport_io)(struct fc_rport *);

/* allocation lengths for host-specific data */
u32 dd_fcrport_size;

Expand Down

0 comments on commit 5e0ff33

Please sign in to comment.