diff options
Diffstat (limited to 'drivers/md')
-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 575317037ce2..204bf42c9449 100644 --- a/drivers/md/dm-mpath-hp-sw.c +++ b/drivers/md/dm-mpath-hp-sw.c | |||
@@ -18,19 +18,54 @@ | |||
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <scsi/scsi.h> | 19 | #include <scsi/scsi.h> |
20 | #include <scsi/scsi_cmnd.h> | 20 | #include <scsi/scsi_cmnd.h> |
21 | #include <scsi/scsi_dbg.h> | ||
21 | 22 | ||
22 | #include "dm.h" | 23 | #include "dm.h" |
23 | #include "dm-hw-handler.h" | 24 | #include "dm-hw-handler.h" |
24 | 25 | ||
25 | #define DM_MSG_PREFIX "multipath hp-sw" | 26 | #define DM_MSG_PREFIX "multipath hp-sw" |
26 | #define DM_HP_HWH_NAME "hp-sw" | 27 | #define DM_HP_HWH_NAME "hp-sw" |
27 | #define DM_HP_HWH_VER "0.0.3" | 28 | #define DM_HP_HWH_VER "1.0.0" |
28 | 29 | ||
29 | struct hp_sw_context { | 30 | struct hp_sw_context { |
30 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | 31 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; |
31 | }; | 32 | }; |
32 | 33 | ||
33 | /* | 34 | /* |
35 | * hp_sw_error_is_retryable - Is an HP-specific check condition retryable? | ||
36 | * @req: path activation request | ||
37 | * | ||
38 | * Examine error codes of request and determine whether the error is retryable. | ||
39 | * Some error codes are already retried by scsi-ml (see | ||
40 | * scsi_decide_disposition), but some HP specific codes are not. | ||
41 | * The intent of this routine is to supply the logic for the HP specific | ||
42 | * check conditions. | ||
43 | * | ||
44 | * Returns: | ||
45 | * 1 - command completed with retryable error | ||
46 | * 0 - command completed with non-retryable error | ||
47 | * | ||
48 | * Possible optimizations | ||
49 | * 1. More hardware-specific error codes | ||
50 | */ | ||
51 | static int hp_sw_error_is_retryable(struct request *req) | ||
52 | { | ||
53 | /* | ||
54 | * NOT_READY is known to be retryable | ||
55 | * For now we just dump out the sense data and call it retryable | ||
56 | */ | ||
57 | if (status_byte(req->errors) == CHECK_CONDITION) | ||
58 | __scsi_print_sense(DM_HP_HWH_NAME, req->sense, req->sense_len); | ||
59 | |||
60 | /* | ||
61 | * At this point we don't have complete information about all the error | ||
62 | * codes from this hardware, so we are just conservative and retry | ||
63 | * when in doubt. | ||
64 | */ | ||
65 | return 1; | ||
66 | } | ||
67 | |||
68 | /* | ||
34 | * hp_sw_end_io - Completion handler for HP path activation. | 69 | * hp_sw_end_io - Completion handler for HP path activation. |
35 | * @req: path activation request | 70 | * @req: path activation request |
36 | * @error: scsi-ml error | 71 | * @error: scsi-ml error |
@@ -40,23 +75,30 @@ struct hp_sw_context { | |||
40 | * | 75 | * |
41 | * Context: scsi-ml softirq | 76 | * Context: scsi-ml softirq |
42 | * | 77 | * |
43 | * Possible optimizations | ||
44 | * 1. Actually check sense data for retryable error (e.g. NOT_READY) | ||
45 | */ | 78 | */ |
46 | static void hp_sw_end_io(struct request *req, int error) | 79 | static void hp_sw_end_io(struct request *req, int error) |
47 | { | 80 | { |
48 | struct dm_path *path = req->end_io_data; | 81 | struct dm_path *path = req->end_io_data; |
49 | unsigned err_flags = 0; | 82 | unsigned err_flags = 0; |
50 | 83 | ||
51 | if (!error) | 84 | if (!error) { |
52 | DMDEBUG("%s path activation command - success", | 85 | DMDEBUG("%s path activation command - success", |
53 | path->dev->name); | 86 | path->dev->name); |
54 | else { | 87 | goto out; |
55 | DMWARN("%s path activation command - error=0x%x", | ||
56 | path->dev->name, error); | ||
57 | err_flags = MP_FAIL_PATH; | ||
58 | } | 88 | } |
59 | 89 | ||
90 | if (hp_sw_error_is_retryable(req)) { | ||
91 | DMDEBUG("%s path activation command - retry", | ||
92 | path->dev->name); | ||
93 | err_flags = MP_RETRY; | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | DMWARN("%s path activation fail - error=0x%x", | ||
98 | path->dev->name, error); | ||
99 | err_flags = MP_FAIL_PATH; | ||
100 | |||
101 | out: | ||
60 | req->end_io_data = NULL; | 102 | req->end_io_data = NULL; |
61 | __blk_put_request(req->q, req); | 103 | __blk_put_request(req->q, req); |
62 | dm_pg_init_complete(path, err_flags); | 104 | dm_pg_init_complete(path, err_flags); |
@@ -135,7 +177,7 @@ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, | |||
135 | if (!req) { | 177 | if (!req) { |
136 | DMERR("%s path activation command - allocation fail", | 178 | DMERR("%s path activation command - allocation fail", |
137 | path->dev->name); | 179 | path->dev->name); |
138 | goto fail; | 180 | goto retry; |
139 | } | 181 | } |
140 | 182 | ||
141 | DMDEBUG("%s path activation command - sent", path->dev->name); | 183 | 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, | |||
143 | blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); | 185 | blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); |
144 | return; | 186 | return; |
145 | 187 | ||
146 | fail: | 188 | retry: |
147 | dm_pg_init_complete(path, MP_FAIL_PATH); | 189 | dm_pg_init_complete(path, MP_RETRY); |
148 | } | 190 | } |
149 | 191 | ||
150 | static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) | 192 | static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) |