struct list_head pgpaths;
};
+#define FEATURE_NO_PARTITIONS 1
+
/* Multipath context */
struct multipath {
struct list_head list;
unsigned saved_queue_if_no_path;/* Saved state during suspension */
unsigned pg_init_retries; /* Number of times to retry pg_init */
unsigned pg_init_count; /* Number of times pg_init called */
+ unsigned features; /* Additional selected features */
struct work_struct process_queued_ios;
struct list_head queued_ios;
m->pg_init_count++;
m->pg_init_required = 0;
list_for_each_entry(tmp, &pgpath->pg->pgpaths, list) {
+ /* Skip disabled paths or failed paths */
+ if (!tmp->path.dev || !tmp->is_active)
+ continue;
if (queue_work(kmpath_handlerd, &tmp->activate_path))
m->pg_init_in_progress++;
}
continue;
}
+ if (!strnicmp(param_name, MESG_STR("no_partitions"))) {
+ m->features |= FEATURE_NO_PARTITIONS;
+ continue;
+ }
if (!strnicmp(param_name, MESG_STR("pg_init_retries")) &&
(argc >= 1)) {
r = read_param(_params + 1, shift(as),
errors = 0;
break;
}
- DMERR("Cannot failover device because scsi_dh_%s was not "
- "loaded.", m->hw_handler_name);
+ DMERR("Cannot failover device %s because scsi_dh_%s was not "
+ "loaded.", pgpath->path.pdev, m->hw_handler_name);
/*
* Fail path for now, so we do not ping pong
*/
*/
bypass_pg(m, pg, 1);
break;
+ case SCSI_DH_DEV_OFFLINED:
+ DMWARN("Device %s offlined.", pgpath->path.pdev);
+ errors = 0;
+ break;
/* TODO: For SCSI_DH_RETRY we should wait a couple seconds */
case SCSI_DH_RETRY:
case SCSI_DH_IMM_RETRY:
spin_lock_irqsave(&m->lock, flags);
if (errors) {
if (pgpath == m->current_pgpath) {
- DMERR("Could not failover device. Error %d.", errors);
+ DMERR("Could not failover device %s, error %d.",
+ pgpath->path.pdev, errors);
m->current_pgpath = NULL;
m->current_pg = NULL;
}
DMEMIT("2 %u %u ", m->queue_size, m->pg_init_count);
else {
DMEMIT("%u ", m->queue_if_no_path +
- (m->pg_init_retries > 0) * 2);
+ (m->pg_init_retries > 0) * 2 +
+ (m->features & FEATURE_NO_PARTITIONS));
if (m->queue_if_no_path)
DMEMIT("queue_if_no_path ");
if (m->pg_init_retries)
DMEMIT("pg_init_retries %u ", m->pg_init_retries);
+ if (m->features & FEATURE_NO_PARTITIONS)
+ DMEMIT("no_partitions ");
}
if (!m->hw_handler_name || type == STATUSTYPE_INFO)
dd_new = dd_old = *dd;
- dd_new.dm_dev.mode |= new_mode;
+ dd_new.dm_dev.mode = new_mode;
dd_new.dm_dev.bdev = NULL;
r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md);
- if (r)
+ if (r == -EROFS) {
+ dd_new.dm_dev.mode &= ~FMODE_WRITE;
+ r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md);
+ }
+ if (!r)
return r;
- dd->dm_dev.mode |= new_mode;
+ dd->dm_dev.mode = new_mode;
close_dev(&dd_old, md);
return 0;
atomic_set(&dd->count, 0);
list_add(&dd->list, &t->devices);
- } else if (dd->dm_dev.mode != (mode | dd->dm_dev.mode)) {
+ } else if (dd->dm_dev.mode != mode) {
r = upgrade_mode(dd, mode, t->md);
if (r)
return r;
int len = 0;
rq = blk_get_request(sdev->request_queue,
- (cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO);
+ (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
if (!rq) {
sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
return NULL;
len = sizeof(short_trespass);
rq->cmd_flags |= REQ_RW;
rq->cmd[1] = 0x10;
+ rq->cmd[4] = len;
break;
case MODE_SELECT_10:
len = sizeof(long_trespass);
rq->cmd_flags |= REQ_RW;
rq->cmd[1] = 0x10;
+ rq->cmd[8] = len;
break;
case INQUIRY:
len = CLARIION_BUFFER_SIZE;
+ rq->cmd[4] = len;
memset(buffer, 0, len);
break;
default:
break;
}
- rq->cmd[4] = len;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
REQ_FAILFAST_DRIVER;