1/* 2 * CCW device PGID and path verification I/O handling. 3 * 4 * Copyright IBM Corp. 2002,2009 5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com> 7 * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 8 */ 9 10#include <linux/kernel.h> 11#include <linux/string.h> 12#include <linux/types.h> 13#include <linux/errno.h> 14#include <linux/bitops.h> 15#include <asm/ccwdev.h> 16#include <asm/cio.h> 17 18#include "cio.h" 19#include "cio_debug.h" 20#include "device.h" 21#include "io_sch.h" 22 23#define PGID_RETRIES 256 24#define PGID_TIMEOUT (10 * HZ) 25 26/* 27 * Process path verification data and report result. 28 */ 29static void verify_done(struct ccw_device *cdev, int rc) 30{ 31 struct subchannel *sch = to_subchannel(cdev->dev.parent); 32 struct ccw_dev_id *id = &cdev->private->dev_id; 33 int mpath = cdev->private->flags.mpath; 34 int pgroup = cdev->private->flags.pgroup; 35 36 if (rc) 37 goto out; 38 /* Ensure consistent multipathing state at device and channel. */ 39 if (sch->config.mp != mpath) { 40 sch->config.mp = mpath; 41 rc = cio_commit_config(sch); 42 } 43out: 44 CIO_MSG_EVENT(2, "vrfy: device 0.%x.%04x: rc=%d pgroup=%d mpath=%d " 45 "vpm=%02x\n", id->ssid, id->devno, rc, pgroup, mpath, 46 sch->vpm); 47 ccw_device_verify_done(cdev, rc); 48} 49 50/* 51 * Create channel program to perform a NOOP. 52 */ 53static void nop_build_cp(struct ccw_device *cdev) 54{ 55 struct ccw_request *req = &cdev->private->req; 56 struct ccw1 *cp = cdev->private->iccws; 57 58 cp->cmd_code = CCW_CMD_NOOP; 59 cp->cda = 0; 60 cp->count = 0; 61 cp->flags = CCW_FLAG_SLI; 62 req->cp = cp; 63} 64 65/* 66 * Perform NOOP on a single path. 67 */ 68static void nop_do(struct ccw_device *cdev) 69{ 70 struct subchannel *sch = to_subchannel(cdev->dev.parent); 71 struct ccw_request *req = &cdev->private->req; 72 73 /* Adjust lpm. */ 74 req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & sch->opm); 75 if (!req->lpm) 76 goto out_nopath; 77 nop_build_cp(cdev); 78 ccw_request_start(cdev); 79 return; 80 81out_nopath: 82 verify_done(cdev, sch->vpm ? 0 : -EACCES); 83} 84 85/* 86 * Adjust NOOP I/O status. 87 */ 88static enum io_status nop_filter(struct ccw_device *cdev, void *data, 89 struct irb *irb, enum io_status status) 90{ 91 /* Only subchannel status might indicate a path error. */ 92 if (status == IO_STATUS_ERROR && irb->scsw.cmd.cstat == 0) 93 return IO_DONE; 94 return status; 95} 96 97/* 98 * Process NOOP request result for a single path. 99 */ 100static void nop_callback(struct ccw_device *cdev, void *data, int rc) 101{ 102 struct subchannel *sch = to_subchannel(cdev->dev.parent); 103 struct ccw_request *req = &cdev->private->req; 104 105 if (rc == 0) 106 sch->vpm |= req->lpm; 107 else if (rc != -EACCES) 108 goto err; 109 req->lpm >>= 1; 110 nop_do(cdev); 111 return; 112 113err: 114 verify_done(cdev, rc); 115} 116 117/* 118 * Create channel program to perform SET PGID on a single path. 119 */ 120static void spid_build_cp(struct ccw_device *cdev, u8 fn) 121{ 122 struct ccw_request *req = &cdev->private->req; 123 struct ccw1 *cp = cdev->private->iccws; 124 int i = 8 - ffs(req->lpm); 125 struct pgid *pgid = &cdev->private->pgid[i]; 126 127 pgid->inf.fc = fn; 128 cp->cmd_code = CCW_CMD_SET_PGID; 129 cp->cda = (u32) (addr_t) pgid; 130 cp->count = sizeof(*pgid); 131 cp->flags = CCW_FLAG_SLI; 132 req->cp = cp; 133} 134 135/* 136 * Perform establish/resign SET PGID on a single path. 137 */ 138static void spid_do(struct ccw_device *cdev) 139{ 140 struct subchannel *sch = to_subchannel(cdev->dev.parent); 141 struct ccw_request *req = &cdev->private->req; 142 u8 fn; 143 144 /* Use next available path that is not already in correct state. */ 145 req->lpm = lpm_adjust(req->lpm, cdev->private->pgid_todo_mask); 146 if (!req->lpm) 147 goto out_nopath; 148 /* Channel program setup. */ 149 if (req->lpm & sch->opm) 150 fn = SPID_FUNC_ESTABLISH; 151 else 152 fn = SPID_FUNC_RESIGN; 153 if (cdev->private->flags.mpath) 154 fn |= SPID_FUNC_MULTI_PATH; 155 spid_build_cp(cdev, fn); 156 ccw_request_start(cdev); 157 return; 158 159out_nopath: 160 verify_done(cdev, sch->vpm ? 0 : -EACCES); 161} 162 163static void verify_start(struct ccw_device *cdev); 164 165/* 166 * Process SET PGID request result for a single path. 167 */ 168static void spid_callback(struct ccw_device *cdev, void *data, int rc) 169{ 170 struct subchannel *sch = to_subchannel(cdev->dev.parent); 171 struct ccw_request *req = &cdev->private->req; 172 173 switch (rc) { 174 case 0: 175 sch->vpm |= req->lpm & sch->opm; 176 break; 177 case -EACCES: 178 break; 179 case -EOPNOTSUPP: 180 if (cdev->private->flags.mpath) { 181 /* Try without multipathing. */ 182 cdev->private->flags.mpath = 0; 183 goto out_restart; 184 } 185 /* Try without pathgrouping. */ 186 cdev->private->flags.pgroup = 0; 187 goto out_restart; 188 default: 189 goto err; 190 } 191 req->lpm >>= 1; 192 spid_do(cdev); 193 return; 194 195out_restart: 196 verify_start(cdev); 197 return; 198err: 199 verify_done(cdev, rc); 200} 201 202static void spid_start(struct ccw_device *cdev) 203{ 204 struct ccw_request *req = &cdev->private->req; 205 206 /* Initialize request data. */ 207 memset(req, 0, sizeof(*req)); 208 req->timeout = PGID_TIMEOUT; 209 req->maxretries = PGID_RETRIES; 210 req->lpm = 0x80; 211 req->singlepath = 1; 212 req->callback = spid_callback; 213 spid_do(cdev); 214} 215 216static int pgid_cmp(struct pgid *p1, struct pgid *p2) 217{ 218 return memcmp((char *) p1 + 1, (char *) p2 + 1, 219 sizeof(struct pgid) - 1); 220} 221 222/* 223 * Determine pathgroup state from PGID data. 224 */ 225static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, 226 int *mismatch, int *reserved, int *reset) 227{ 228 struct pgid *pgid = &cdev->private->pgid[0]; 229 struct pgid *first = NULL; 230 int lpm; 231 int i; 232 233 *mismatch = 0; 234 *reserved = 0; 235 *reset = 0; 236 for (i = 0, lpm = 0x80; i < 8; i++, pgid++, lpm >>= 1) { 237 if ((cdev->private->pgid_valid_mask & lpm) == 0) 238 continue; 239 if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE) 240 *reserved = 1; 241 if (pgid->inf.ps.state1 == SNID_STATE1_RESET) { 242 /* A PGID was reset. */ 243 *reset = 1; 244 continue; 245 } 246 if (!first) { 247 first = pgid; 248 continue; 249 } 250 if (pgid_cmp(pgid, first) != 0) 251 *mismatch = 1; 252 } 253 if (!first) 254 first = &channel_subsystems[0]->global_pgid; 255 *p = first; 256} 257 258static u8 pgid_to_donepm(struct ccw_device *cdev) 259{ 260 struct subchannel *sch = to_subchannel(cdev->dev.parent); 261 struct pgid *pgid; 262 int i; 263 int lpm; 264 u8 donepm = 0; 265 266 /* Set bits for paths which are already in the target state. */ 267 for (i = 0; i < 8; i++) { 268 lpm = 0x80 >> i; 269 if ((cdev->private->pgid_valid_mask & lpm) == 0) 270 continue; 271 pgid = &cdev->private->pgid[i]; 272 if (sch->opm & lpm) { 273 if (pgid->inf.ps.state1 != SNID_STATE1_GROUPED) 274 continue; 275 } else { 276 if (pgid->inf.ps.state1 != SNID_STATE1_UNGROUPED) 277 continue; 278 } 279 if (cdev->private->flags.mpath) { 280 if (pgid->inf.ps.state3 != SNID_STATE3_MULTI_PATH) 281 continue; 282 } else { 283 if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH) 284 continue; 285 } 286 donepm |= lpm; 287 } 288 289 return donepm; 290} 291 292static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid) 293{ 294 int i; 295 296 for (i = 0; i < 8; i++) 297 memcpy(&cdev->private->pgid[i], pgid, sizeof(struct pgid)); 298} 299 300/* 301 * Process SENSE PGID data and report result. 302 */ 303static void snid_done(struct ccw_device *cdev, int rc) 304{ 305 struct ccw_dev_id *id = &cdev->private->dev_id; 306 struct subchannel *sch = to_subchannel(cdev->dev.parent); 307 struct pgid *pgid; 308 int mismatch = 0; 309 int reserved = 0; 310 int reset = 0; 311 u8 donepm; 312 313 if (rc) 314 goto out; 315 pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset); 316 if (reserved) 317 rc = -EUSERS; 318 else if (mismatch) 319 rc = -EOPNOTSUPP; 320 else { 321 donepm = pgid_to_donepm(cdev); 322 sch->vpm = donepm & sch->opm; 323 cdev->private->pgid_todo_mask &= ~donepm; 324 pgid_fill(cdev, pgid); 325 } 326out: 327 CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " 328 "todo=%02x mism=%d rsvd=%d reset=%d\n", id->ssid, 329 id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm, 330 cdev->private->pgid_todo_mask, mismatch, reserved, reset); 331 switch (rc) { 332 case 0: 333 /* Anything left to do? */ 334 if (cdev->private->pgid_todo_mask == 0) { 335 verify_done(cdev, sch->vpm == 0 ? -EACCES : 0); 336 return; 337 } 338 /* Perform path-grouping. */ 339 spid_start(cdev); 340 break; 341 case -EOPNOTSUPP: 342 /* Path-grouping not supported. */ 343 cdev->private->flags.pgroup = 0; 344 cdev->private->flags.mpath = 0; 345 verify_start(cdev); 346 break; 347 default: 348 verify_done(cdev, rc); 349 } 350} 351 352/* 353 * Create channel program to perform a SENSE PGID on a single path. 354 */ 355static void snid_build_cp(struct ccw_device *cdev) 356{ 357 struct ccw_request *req = &cdev->private->req; 358 struct ccw1 *cp = cdev->private->iccws; 359 int i = 8 - ffs(req->lpm); 360 361 /* Channel program setup. */ 362 cp->cmd_code = CCW_CMD_SENSE_PGID; 363 cp->cda = (u32) (addr_t) &cdev->private->pgid[i]; 364 cp->count = sizeof(struct pgid); 365 cp->flags = CCW_FLAG_SLI; 366 req->cp = cp; 367} 368 369/* 370 * Perform SENSE PGID on a single path. 371 */ 372static void snid_do(struct ccw_device *cdev) 373{ 374 struct subchannel *sch = to_subchannel(cdev->dev.parent); 375 struct ccw_request *req = &cdev->private->req; 376 377 /* Adjust lpm if paths are not set in pam. */ 378 req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam); 379 if (!req->lpm) 380 goto out_nopath; 381 snid_build_cp(cdev); 382 ccw_request_start(cdev); 383 return; 384 385out_nopath: 386 snid_done(cdev, cdev->private->pgid_valid_mask ? 0 : -EACCES); 387} 388 389/* 390 * Process SENSE PGID request result for single path. 391 */ 392static void snid_callback(struct ccw_device *cdev, void *data, int rc) 393{ 394 struct ccw_request *req = &cdev->private->req; 395 396 if (rc == 0) 397 cdev->private->pgid_valid_mask |= req->lpm; 398 else if (rc != -EACCES) 399 goto err; 400 req->lpm >>= 1; 401 snid_do(cdev); 402 return; 403 404err: 405 snid_done(cdev, rc); 406} 407 408/* 409 * Perform path verification. 410 */ 411static void verify_start(struct ccw_device *cdev) 412{ 413 struct subchannel *sch = to_subchannel(cdev->dev.parent); 414 struct ccw_request *req = &cdev->private->req; 415 struct ccw_dev_id *devid = &cdev->private->dev_id; 416 417 sch->vpm = 0; 418 sch->lpm = sch->schib.pmcw.pam; 419 /* Initialize request data. */ 420 memset(req, 0, sizeof(*req)); 421 req->timeout = PGID_TIMEOUT; 422 req->maxretries = PGID_RETRIES; 423 req->lpm = 0x80; 424 req->singlepath = 1; 425 if (cdev->private->flags.pgroup) { 426 CIO_TRACE_EVENT(4, "snid"); 427 CIO_HEX_EVENT(4, devid, sizeof(*devid)); 428 req->callback = snid_callback; 429 snid_do(cdev); 430 } else { 431 CIO_TRACE_EVENT(4, "nop"); 432 CIO_HEX_EVENT(4, devid, sizeof(*devid)); 433 req->filter = nop_filter; 434 req->callback = nop_callback; 435 nop_do(cdev); 436 } 437} 438 439/** 440 * ccw_device_verify_start - perform path verification 441 * @cdev: ccw device 442 * 443 * Perform an I/O on each available channel path to @cdev to determine which 444 * paths are operational. The resulting path mask is stored in sch->vpm. 445 * If device options specify pathgrouping, establish a pathgroup for the 446 * operational paths. When finished, call ccw_device_verify_done with a 447 * return code specifying the result. 448 */ 449void ccw_device_verify_start(struct ccw_device *cdev) 450{ 451 struct subchannel *sch = to_subchannel(cdev->dev.parent); 452 453 CIO_TRACE_EVENT(4, "vrfy"); 454 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); 455 /* Initialize PGID data. */ 456 memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); 457 cdev->private->pgid_valid_mask = 0; 458 cdev->private->pgid_todo_mask = sch->schib.pmcw.pam; 459 /* 460 * Initialize pathgroup and multipath state with target values. 461 * They may change in the course of path verification. 462 */ 463 cdev->private->flags.pgroup = cdev->private->options.pgroup; 464 cdev->private->flags.mpath = cdev->private->options.mpath; 465 cdev->private->flags.doverify = 0; 466 verify_start(cdev); 467} 468 469/* 470 * Process disband SET PGID request result. 471 */ 472static void disband_callback(struct ccw_device *cdev, void *data, int rc) 473{ 474 struct subchannel *sch = to_subchannel(cdev->dev.parent); 475 struct ccw_dev_id *id = &cdev->private->dev_id; 476 477 if (rc) 478 goto out; 479 /* Ensure consistent multipathing state at device and channel. */ 480 cdev->private->flags.mpath = 0; 481 if (sch->config.mp) { 482 sch->config.mp = 0; 483 rc = cio_commit_config(sch); 484 } 485out: 486 CIO_MSG_EVENT(0, "disb: device 0.%x.%04x: rc=%d\n", id->ssid, id->devno, 487 rc); 488 ccw_device_disband_done(cdev, rc); 489} 490 491/** 492 * ccw_device_disband_start - disband pathgroup 493 * @cdev: ccw device 494 * 495 * Execute a SET PGID channel program on @cdev to disband a previously 496 * established pathgroup. When finished, call ccw_device_disband_done with 497 * a return code specifying the result. 498 */ 499void ccw_device_disband_start(struct ccw_device *cdev) 500{ 501 struct subchannel *sch = to_subchannel(cdev->dev.parent); 502 struct ccw_request *req = &cdev->private->req; 503 u8 fn; 504 505 CIO_TRACE_EVENT(4, "disb"); 506 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); 507 /* Request setup. */ 508 memset(req, 0, sizeof(*req)); 509 req->timeout = PGID_TIMEOUT; 510 req->maxretries = PGID_RETRIES; 511 req->lpm = sch->schib.pmcw.pam & sch->opm; 512 req->singlepath = 1; 513 req->callback = disband_callback; 514 fn = SPID_FUNC_DISBAND; 515 if (cdev->private->flags.mpath) 516 fn |= SPID_FUNC_MULTI_PATH; 517 spid_build_cp(cdev, fn); 518 ccw_request_start(cdev); 519} 520 521static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2) 522{ 523 struct ccw_request *req = &cdev->private->req; 524 struct ccw1 *cp = cdev->private->iccws; 525 526 cp[0].cmd_code = CCW_CMD_STLCK; 527 cp[0].cda = (u32) (addr_t) buf1; 528 cp[0].count = 32; 529 cp[0].flags = CCW_FLAG_CC; 530 cp[1].cmd_code = CCW_CMD_RELEASE; 531 cp[1].cda = (u32) (addr_t) buf2; 532 cp[1].count = 32; 533 cp[1].flags = 0; 534 req->cp = cp; 535} 536 537static void stlck_callback(struct ccw_device *cdev, void *data, int rc) 538{ 539 ccw_device_stlck_done(cdev, data, rc); 540} 541 542/** 543 * ccw_device_stlck_start - perform unconditional release 544 * @cdev: ccw device 545 * @data: data pointer to be passed to ccw_device_stlck_done 546 * @buf1: data pointer used in channel program 547 * @buf2: data pointer used in channel program 548 * 549 * Execute a channel program on @cdev to release an existing PGID reservation. 550 * When finished, call ccw_device_stlck_done with a return code specifying the 551 * result. 552 */ 553void ccw_device_stlck_start(struct ccw_device *cdev, void *data, void *buf1, 554 void *buf2) 555{ 556 struct subchannel *sch = to_subchannel(cdev->dev.parent); 557 struct ccw_request *req = &cdev->private->req; 558 559 CIO_TRACE_EVENT(4, "stlck"); 560 CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); 561 /* Request setup. */ 562 memset(req, 0, sizeof(*req)); 563 req->timeout = PGID_TIMEOUT; 564 req->maxretries = PGID_RETRIES; 565 req->lpm = sch->schib.pmcw.pam & sch->opm; 566 req->data = data; 567 req->callback = stlck_callback; 568 stlck_build_cp(cdev, buf1, buf2); 569 ccw_request_start(cdev); 570} 571