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-rc6 347 lines 8.2 kB view raw
1/* 2 * Copyright (C) 2004 SUSE LINUX Products GmbH. All rights reserved. 3 * Copyright (C) 2004 Red Hat, Inc. All rights reserved. 4 * 5 * This file is released under the GPL. 6 * 7 * Multipath support for EMC CLARiiON AX/CX-series hardware. 8 */ 9 10#include "dm.h" 11#include "dm-hw-handler.h" 12#include <scsi/scsi.h> 13#include <scsi/scsi_cmnd.h> 14 15#define DM_MSG_PREFIX "multipath emc" 16 17struct emc_handler { 18 spinlock_t lock; 19 20 /* Whether we should send the short trespass command (FC-series) 21 * or the long version (default for AX/CX CLARiiON arrays). */ 22 unsigned short_trespass; 23 /* Whether or not to honor SCSI reservations when initiating a 24 * switch-over. Default: Don't. */ 25 unsigned hr; 26 27 unsigned char sense[SCSI_SENSE_BUFFERSIZE]; 28}; 29 30#define TRESPASS_PAGE 0x22 31#define EMC_FAILOVER_TIMEOUT (60 * HZ) 32 33/* Code borrowed from dm-lsi-rdac by Mike Christie */ 34 35static inline void free_bio(struct bio *bio) 36{ 37 __free_page(bio->bi_io_vec[0].bv_page); 38 bio_put(bio); 39} 40 41static void emc_endio(struct bio *bio, int error) 42{ 43 struct dm_path *path = bio->bi_private; 44 45 /* We also need to look at the sense keys here whether or not to 46 * switch to the next PG etc. 47 * 48 * For now simple logic: either it works or it doesn't. 49 */ 50 if (error) 51 dm_pg_init_complete(path, MP_FAIL_PATH); 52 else 53 dm_pg_init_complete(path, 0); 54 55 /* request is freed in block layer */ 56 free_bio(bio); 57} 58 59static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size) 60{ 61 struct bio *bio; 62 struct page *page; 63 64 bio = bio_alloc(GFP_ATOMIC, 1); 65 if (!bio) { 66 DMERR("get_failover_bio: bio_alloc() failed."); 67 return NULL; 68 } 69 70 bio->bi_rw |= (1 << BIO_RW); 71 bio->bi_bdev = path->dev->bdev; 72 bio->bi_sector = 0; 73 bio->bi_private = path; 74 bio->bi_end_io = emc_endio; 75 76 page = alloc_page(GFP_ATOMIC); 77 if (!page) { 78 DMERR("get_failover_bio: alloc_page() failed."); 79 bio_put(bio); 80 return NULL; 81 } 82 83 if (bio_add_page(bio, page, data_size, 0) != data_size) { 84 DMERR("get_failover_bio: bio_add_page() failed."); 85 __free_page(page); 86 bio_put(bio); 87 return NULL; 88 } 89 90 return bio; 91} 92 93static struct request *get_failover_req(struct emc_handler *h, 94 struct bio *bio, struct dm_path *path) 95{ 96 struct request *rq; 97 struct block_device *bdev = bio->bi_bdev; 98 struct request_queue *q = bdev_get_queue(bdev); 99 100 /* FIXME: Figure out why it fails with GFP_ATOMIC. */ 101 rq = blk_get_request(q, WRITE, __GFP_WAIT); 102 if (!rq) { 103 DMERR("get_failover_req: blk_get_request failed"); 104 return NULL; 105 } 106 107 blk_rq_append_bio(q, rq, bio); 108 109 rq->sense = h->sense; 110 memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); 111 rq->sense_len = 0; 112 113 memset(&rq->cmd, 0, BLK_MAX_CDB); 114 115 rq->timeout = EMC_FAILOVER_TIMEOUT; 116 rq->cmd_type = REQ_TYPE_BLOCK_PC; 117 rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; 118 119 return rq; 120} 121 122static struct request *emc_trespass_get(struct emc_handler *h, 123 struct dm_path *path) 124{ 125 struct bio *bio; 126 struct request *rq; 127 unsigned char *page22; 128 unsigned char long_trespass_pg[] = { 129 0, 0, 0, 0, 130 TRESPASS_PAGE, /* Page code */ 131 0x09, /* Page length - 2 */ 132 h->hr ? 0x01 : 0x81, /* Trespass code + Honor reservation bit */ 133 0xff, 0xff, /* Trespass target */ 134 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ 135 }; 136 unsigned char short_trespass_pg[] = { 137 0, 0, 0, 0, 138 TRESPASS_PAGE, /* Page code */ 139 0x02, /* Page length - 2 */ 140 h->hr ? 0x01 : 0x81, /* Trespass code + Honor reservation bit */ 141 0xff, /* Trespass target */ 142 }; 143 unsigned data_size = h->short_trespass ? sizeof(short_trespass_pg) : 144 sizeof(long_trespass_pg); 145 146 /* get bio backing */ 147 if (data_size > PAGE_SIZE) 148 /* this should never happen */ 149 return NULL; 150 151 bio = get_failover_bio(path, data_size); 152 if (!bio) { 153 DMERR("emc_trespass_get: no bio"); 154 return NULL; 155 } 156 157 page22 = (unsigned char *)bio_data(bio); 158 memset(page22, 0, data_size); 159 160 memcpy(page22, h->short_trespass ? 161 short_trespass_pg : long_trespass_pg, data_size); 162 163 /* get request for block layer packet command */ 164 rq = get_failover_req(h, bio, path); 165 if (!rq) { 166 DMERR("emc_trespass_get: no rq"); 167 free_bio(bio); 168 return NULL; 169 } 170 171 /* Prepare the command. */ 172 rq->cmd[0] = MODE_SELECT; 173 rq->cmd[1] = 0x10; 174 rq->cmd[4] = data_size; 175 rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); 176 177 return rq; 178} 179 180static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed, 181 struct dm_path *path) 182{ 183 struct request *rq; 184 struct request_queue *q = bdev_get_queue(path->dev->bdev); 185 186 /* 187 * We can either blindly init the pg (then look at the sense), 188 * or we can send some commands to get the state here (then 189 * possibly send the fo cmnd), or we can also have the 190 * initial state passed into us and then get an update here. 191 */ 192 if (!q) { 193 DMINFO("emc_pg_init: no queue"); 194 goto fail_path; 195 } 196 197 /* FIXME: The request should be pre-allocated. */ 198 rq = emc_trespass_get(hwh->context, path); 199 if (!rq) { 200 DMERR("emc_pg_init: no rq"); 201 goto fail_path; 202 } 203 204 DMINFO("emc_pg_init: sending switch-over command"); 205 elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); 206 return; 207 208fail_path: 209 dm_pg_init_complete(path, MP_FAIL_PATH); 210} 211 212static struct emc_handler *alloc_emc_handler(void) 213{ 214 struct emc_handler *h = kzalloc(sizeof(*h), GFP_KERNEL); 215 216 if (h) 217 spin_lock_init(&h->lock); 218 219 return h; 220} 221 222static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv) 223{ 224 struct emc_handler *h; 225 unsigned hr, short_trespass; 226 227 if (argc == 0) { 228 /* No arguments: use defaults */ 229 hr = 0; 230 short_trespass = 0; 231 } else if (argc != 2) { 232 DMWARN("incorrect number of arguments"); 233 return -EINVAL; 234 } else { 235 if ((sscanf(argv[0], "%u", &short_trespass) != 1) 236 || (short_trespass > 1)) { 237 DMWARN("invalid trespass mode selected"); 238 return -EINVAL; 239 } 240 241 if ((sscanf(argv[1], "%u", &hr) != 1) 242 || (hr > 1)) { 243 DMWARN("invalid honor reservation flag selected"); 244 return -EINVAL; 245 } 246 } 247 248 h = alloc_emc_handler(); 249 if (!h) 250 return -ENOMEM; 251 252 hwh->context = h; 253 254 if ((h->short_trespass = short_trespass)) 255 DMWARN("short trespass command will be send"); 256 else 257 DMWARN("long trespass command will be send"); 258 259 if ((h->hr = hr)) 260 DMWARN("honor reservation bit will be set"); 261 else 262 DMWARN("honor reservation bit will not be set (default)"); 263 264 return 0; 265} 266 267static void emc_destroy(struct hw_handler *hwh) 268{ 269 struct emc_handler *h = (struct emc_handler *) hwh->context; 270 271 kfree(h); 272 hwh->context = NULL; 273} 274 275static unsigned emc_error(struct hw_handler *hwh, struct bio *bio) 276{ 277 /* FIXME: Patch from axboe still missing */ 278#if 0 279 int sense; 280 281 if (bio->bi_error & BIO_SENSE) { 282 sense = bio->bi_error & 0xffffff; /* sense key / asc / ascq */ 283 284 if (sense == 0x020403) { 285 /* LUN Not Ready - Manual Intervention Required 286 * indicates this is a passive path. 287 * 288 * FIXME: However, if this is seen and EVPD C0 289 * indicates that this is due to a NDU in 290 * progress, we should set FAIL_PATH too. 291 * This indicates we might have to do a SCSI 292 * inquiry in the end_io path. Ugh. */ 293 return MP_BYPASS_PG | MP_RETRY_IO; 294 } else if (sense == 0x052501) { 295 /* An array based copy is in progress. Do not 296 * fail the path, do not bypass to another PG, 297 * do not retry. Fail the IO immediately. 298 * (Actually this is the same conclusion as in 299 * the default handler, but lets make sure.) */ 300 return 0; 301 } else if (sense == 0x062900) { 302 /* Unit Attention Code. This is the first IO 303 * to the new path, so just retry. */ 304 return MP_RETRY_IO; 305 } 306 } 307#endif 308 309 /* Try default handler */ 310 return dm_scsi_err_handler(hwh, bio); 311} 312 313static struct hw_handler_type emc_hwh = { 314 .name = "emc", 315 .module = THIS_MODULE, 316 .create = emc_create, 317 .destroy = emc_destroy, 318 .pg_init = emc_pg_init, 319 .error = emc_error, 320}; 321 322static int __init dm_emc_init(void) 323{ 324 int r = dm_register_hw_handler(&emc_hwh); 325 326 if (r < 0) 327 DMERR("register failed %d", r); 328 329 DMINFO("version 0.0.3 loaded"); 330 331 return r; 332} 333 334static void __exit dm_emc_exit(void) 335{ 336 int r = dm_unregister_hw_handler(&emc_hwh); 337 338 if (r < 0) 339 DMERR("unregister failed %d", r); 340} 341 342module_init(dm_emc_init); 343module_exit(dm_emc_exit); 344 345MODULE_DESCRIPTION(DM_NAME " EMC CX/AX/FC-family multipath"); 346MODULE_AUTHOR("Lars Marowsky-Bree <lmb@suse.de>"); 347MODULE_LICENSE("GPL");