diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm-mpath-hp-sw.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c index 575317037ce..204bf42c944 100644 --- a/drivers/md/dm-mpath-hp-sw.c +++ b/drivers/md/dm-mpath-hp-sw.c @@ -18,19 +18,54 @@ #include <linux/types.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> +#include <scsi/scsi_dbg.h> #include "dm.h" #include "dm-hw-handler.h" #define DM_MSG_PREFIX "multipath hp-sw" #define DM_HP_HWH_NAME "hp-sw" -#define DM_HP_HWH_VER "0.0.3" +#define DM_HP_HWH_VER "1.0.0" struct hp_sw_context { unsigned char sense[SCSI_SENSE_BUFFERSIZE]; }; /* + * hp_sw_error_is_retryable - Is an HP-specific check condition retryable? + * @req: path activation request + * + * Examine error codes of request and determine whether the error is retryable. + * Some error codes are already retried by scsi-ml (see + * scsi_decide_disposition), but some HP specific codes are not. + * The intent of this routine is to supply the logic for the HP specific + * check conditions. + * + * Returns: + * 1 - command completed with retryable error + * 0 - command completed with non-retryable error + * + * Possible optimizations + * 1. More hardware-specific error codes + */ +static int hp_sw_error_is_retryable(struct request *req) +{ + /* + * NOT_READY is known to be retryable + * For now we just dump out the sense data and call it retryable + */ + if (status_byte(req->errors) == CHECK_CONDITION) + __scsi_print_sense(DM_HP_HWH_NAME, req->sense, req->sense_len); + + /* + * At this point we don't have complete information about all the error + * codes from this hardware, so we are just conservative and retry + * when in doubt. + */ + return 1; +} + +/* * hp_sw_end_io - Completion handler for HP path activation. * @req: path activation request * @error: scsi-ml error @@ -40,23 +75,30 @@ struct hp_sw_context { * * Context: scsi-ml softirq * - * Possible optimizations - * 1. Actually check sense data for retryable error (e.g. NOT_READY) */ static void hp_sw_end_io(struct request *req, int error) { struct dm_path *path = req->end_io_data; unsigned err_flags = 0; - if (!error) + if (!error) { DMDEBUG("%s path activation command - success", path->dev->name); - else { - DMWARN("%s path activation command - error=0x%x", - path->dev->name, error); - err_flags = MP_FAIL_PATH; + goto out; } + if (hp_sw_error_is_retryable(req)) { + DMDEBUG("%s path activation command - retry", + path->dev->name); + err_flags = MP_RETRY; + goto out; + } + + DMWARN("%s path activation fail - error=0x%x", + path->dev->name, error); + err_flags = MP_FAIL_PATH; + +out: req->end_io_data = NULL; __blk_put_request(req->q, req); dm_pg_init_complete(path, err_flags); @@ -135,7 +177,7 @@ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, if (!req) { DMERR("%s path activation command - allocation fail", path->dev->name); - goto fail; + goto retry; } DMDEBUG("%s path activation command - sent", path->dev->name); @@ -143,8 +185,8 @@ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); return; -fail: - dm_pg_init_complete(path, MP_FAIL_PATH); +retry: + dm_pg_init_complete(path, MP_RETRY); } static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) |