Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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