Blame view
drivers/md/dm-mpath-hp-sw.c
6.23 KB
16ebbf358 dm mpath: add hp ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * Copyright (C) 2005 Mike Christie, All rights reserved. * Copyright (C) 2007 Red Hat, Inc. All rights reserved. * Authors: Mike Christie * Dave Wysochanski * * This file is released under the GPL. * * This module implements the specific path activation code for * HP StorageWorks and FSC FibreCat Asymmetric (Active/Passive) * storage arrays. * These storage arrays have controller-based failover, not * LUN-based failover. However, LUN-based failover is the design * of dm-multipath. Thus, this module is written for LUN-based failover. */ #include <linux/blkdev.h> #include <linux/list.h> #include <linux/types.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> |
fe97e2aa0 dm mpath: hp retr... |
21 |
#include <scsi/scsi_dbg.h> |
16ebbf358 dm mpath: add hp ... |
22 23 24 25 26 27 |
#include "dm.h" #include "dm-hw-handler.h" #define DM_MSG_PREFIX "multipath hp-sw" #define DM_HP_HWH_NAME "hp-sw" |
fe97e2aa0 dm mpath: hp retr... |
28 |
#define DM_HP_HWH_VER "1.0.0" |
16ebbf358 dm mpath: add hp ... |
29 30 31 32 33 34 |
struct hp_sw_context { unsigned char sense[SCSI_SENSE_BUFFERSIZE]; }; /* |
fe97e2aa0 dm mpath: hp retr... |
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
* 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; } /* |
16ebbf358 dm mpath: add hp ... |
69 70 71 72 73 74 75 76 77 |
* hp_sw_end_io - Completion handler for HP path activation. * @req: path activation request * @error: scsi-ml error * * Check sense data, free request structure, and notify dm that * pg initialization has completed. * * Context: scsi-ml softirq * |
16ebbf358 dm mpath: add hp ... |
78 79 80 81 82 |
*/ static void hp_sw_end_io(struct request *req, int error) { struct dm_path *path = req->end_io_data; unsigned err_flags = 0; |
fe97e2aa0 dm mpath: hp retr... |
83 |
if (!error) { |
16ebbf358 dm mpath: add hp ... |
84 85 |
DMDEBUG("%s path activation command - success", path->dev->name); |
fe97e2aa0 dm mpath: hp retr... |
86 |
goto out; |
16ebbf358 dm mpath: add hp ... |
87 |
} |
fe97e2aa0 dm mpath: hp retr... |
88 89 90 91 92 93 94 95 96 97 98 99 |
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: |
16ebbf358 dm mpath: add hp ... |
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
req->end_io_data = NULL; __blk_put_request(req->q, req); dm_pg_init_complete(path, err_flags); } /* * hp_sw_get_request - Allocate an HP specific path activation request * @path: path on which request will be sent (needed for request queue) * * The START command is used for path activation request. * These arrays are controller-based failover, not LUN based. * One START command issued to a single path will fail over all * LUNs for the same controller. * * Possible optimizations * 1. Make timeout configurable * 2. Preallocate request */ static struct request *hp_sw_get_request(struct dm_path *path) { struct request *req; struct block_device *bdev = path->dev->bdev; struct request_queue *q = bdev_get_queue(bdev); struct hp_sw_context *h = path->hwhcontext; req = blk_get_request(q, WRITE, GFP_NOIO); if (!req) goto out; req->timeout = 60 * HZ; req->errors = 0; req->cmd_type = REQ_TYPE_BLOCK_PC; req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; req->end_io_data = path; req->sense = h->sense; memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); |
16ebbf358 dm mpath: add hp ... |
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
req->cmd[0] = START_STOP; req->cmd[4] = 1; req->cmd_len = COMMAND_SIZE(req->cmd[0]); out: return req; } /* * hp_sw_pg_init - HP path activation implementation. * @hwh: hardware handler specific data * @bypassed: unused; is the path group bypassed? (see dm-mpath.c) * @path: path to send initialization command * * Send an HP-specific path activation command on 'path'. * Do not try to optimize in any way, just send the activation command. * More than one path activation command may be sent to the same controller. * This seems to work fine for basic failover support. * * Possible optimizations * 1. Detect an in-progress activation request and avoid submitting another one * 2. Model the controller and only send a single activation request at a time * 3. Determine the state of a path before sending an activation request * * Context: kmpathd (see process_queued_ios() in dm-mpath.c) */ static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed, struct dm_path *path) { struct request *req; struct hp_sw_context *h; path->hwhcontext = hwh->context; h = hwh->context; req = hp_sw_get_request(path); if (!req) { DMERR("%s path activation command - allocation fail", path->dev->name); |
fe97e2aa0 dm mpath: hp retr... |
176 |
goto retry; |
16ebbf358 dm mpath: add hp ... |
177 178 179 180 181 182 |
} DMDEBUG("%s path activation command - sent", path->dev->name); blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io); return; |
fe97e2aa0 dm mpath: hp retr... |
183 184 |
retry: dm_pg_init_complete(path, MP_RETRY); |
16ebbf358 dm mpath: add hp ... |
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
} static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv) { struct hp_sw_context *h; h = kmalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; hwh->context = h; return 0; } static void hp_sw_destroy(struct hw_handler *hwh) { struct hp_sw_context *h = hwh->context; kfree(h); } static struct hw_handler_type hp_sw_hwh = { .name = DM_HP_HWH_NAME, .module = THIS_MODULE, .create = hp_sw_create, .destroy = hp_sw_destroy, .pg_init = hp_sw_pg_init, }; static int __init hp_sw_init(void) { int r; r = dm_register_hw_handler(&hp_sw_hwh); if (r < 0) DMERR("register failed %d", r); else DMINFO("version " DM_HP_HWH_VER " loaded"); return r; } static void __exit hp_sw_exit(void) { int r; r = dm_unregister_hw_handler(&hp_sw_hwh); if (r < 0) DMERR("unregister failed %d", r); } module_init(hp_sw_init); module_exit(hp_sw_exit); MODULE_DESCRIPTION("DM Multipath HP StorageWorks / FSC FibreCat (A/P) support"); MODULE_AUTHOR("Mike Christie, Dave Wysochanski <dm-devel@redhat.com>"); MODULE_LICENSE("GPL"); MODULE_VERSION(DM_HP_HWH_VER); |