--- drivers/md/dm-mpath.c | 66 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 7 deletions(-) Index: linux-2.6/drivers/md/dm-mpath.c =================================================================== --- linux-2.6.orig/drivers/md/dm-mpath.c +++ linux-2.6/drivers/md/dm-mpath.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #define DM_MSG_PREFIX "multipath" @@ -104,6 +105,7 @@ struct multipath { struct dm_mpath_io { struct pgpath *pgpath; size_t nr_bytes; + char sense[SCSI_SENSE_BUFFERSIZE]; }; typedef int (*action_fn) (struct pgpath *pgpath); @@ -960,6 +962,9 @@ static int multipath_map(struct dm_targe map_context->ptr = mpio; clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; + /* Always attach a sense buffer */ + if (!clone->sense) + clone->sense = mpio->sense; r = map_io(m, clone, mpio, 0); if (r < 0 || r == DM_MAPIO_REQUEUE) mempool_free(mpio, m->mpio_pool); @@ -1247,6 +1252,54 @@ static void activate_path(struct work_st pg_init_done, pgpath); } +// TODO: move to scsi_error.c +/* + * Evaluate scsi return code to see if ULD retry is worthwhile. + */ +static bool scsi_uld_should_retry(struct request *req) +{ + struct scsi_sense_hdr sshdr; + int result = req->errors; + char *sense = req->sense; + int sense_len = req->sense_len; + int r = 1; + + if (req->cmd_flags & REQ_DISCARD) + /* + * Pass all discard request failures up. + * FIXME: only fail_path if the discard failed due to a + * transport problem. This requires precise understanding + * of the underlying failure (e.g. the SCSI sense). + */ + return 0; + + if (host_byte(result) != DID_OK) + return r; + + if (msg_byte(result) != COMMAND_COMPLETE) + return r; + + if (status_byte(result) == RESERVATION_CONFLICT) + /* Do not retry here, possible data corruption */ + return 0; + + if (status_byte(result) == CHECK_CONDITION && + !scsi_normalize_sense(sense, sense_len, &sshdr)) { + switch (sshdr.sense_key) { + case MEDIUM_ERROR: + case DATA_PROTECT: + case BLANK_CHECK: + case COPY_ABORTED: + case VOLUME_OVERFLOW: + case MISCOMPARE: + r = 0; + break; + } + } + + return r; +} + /* * end_io handling */ @@ -1273,13 +1326,8 @@ static int do_end_io(struct multipath *m if (error == -EOPNOTSUPP) return error; - if (clone->cmd_flags & REQ_DISCARD) - /* - * Pass all discard request failures up. - * FIXME: only fail_path if the discard failed due to a - * transport problem. This requires precise understanding - * of the underlying failure (e.g. the SCSI sense). - */ + if ((clone->cmd_flags & REQ_SCSI_ERROR) && + !scsi_uld_should_retry(clone)) return error; if (mpio->pgpath) @@ -1308,6 +1356,10 @@ static int multipath_end_io(struct dm_ta if (ps->type->end_io) ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes); } + if (clone->sense == mpio->sense) { + clone->sense = NULL; + clone->sense_len = 0; + } mempool_free(mpio, m->mpio_pool); return r;