diff options
| author | Steve Cameron <scameron@quandary.americas.cpqcorp.net> | 2007-10-17 02:27:37 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:55 -0400 |
| commit | 1a614f505193fcfc1b298643268a5db5b48e297f (patch) | |
| tree | 80413131fca8758fe31e0fb4d383f80f5e75834f /drivers | |
| parent | 7fdfd4065c264bddd2d9277470a6a99d34e01bef (diff) | |
cciss: fix error reporting for SG_IO
This fixes a problem with the way cciss was filling out the "errors" field
of the request structure upon completion of requests. Previously, it just
put a 1 or a 0 in there and used the negation of this as the uptodate
parameter to one of the functions in the block layer, being a block device.
For the SG_IO ioctl, this was not sufficient, and we noticed that, for
example, sg_turs from sg3_utils did not correctly detect problems due to
cciss having set rq->errors incorrectly.
Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
Acked-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/block/cciss.c | 79 |
1 files changed, 61 insertions, 18 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 3fb7e8bc436d..5c269c00d6eb 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
| @@ -2365,30 +2365,55 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) | |||
| 2365 | start_io(h); | 2365 | start_io(h); |
| 2366 | } | 2366 | } |
| 2367 | 2367 | ||
| 2368 | static inline unsigned int make_status_bytes(unsigned int scsi_status_byte, | ||
| 2369 | unsigned int msg_byte, unsigned int host_byte, | ||
| 2370 | unsigned int driver_byte) | ||
| 2371 | { | ||
| 2372 | /* inverse of macros in scsi.h */ | ||
| 2373 | return (scsi_status_byte & 0xff) | | ||
| 2374 | ((msg_byte & 0xff) << 8) | | ||
| 2375 | ((host_byte & 0xff) << 16) | | ||
| 2376 | ((driver_byte & 0xff) << 24); | ||
| 2377 | } | ||
| 2378 | |||
| 2368 | static inline int evaluate_target_status(CommandList_struct *cmd) | 2379 | static inline int evaluate_target_status(CommandList_struct *cmd) |
| 2369 | { | 2380 | { |
| 2370 | unsigned char sense_key; | 2381 | unsigned char sense_key; |
| 2371 | int error_count = 1; | 2382 | unsigned char status_byte, msg_byte, host_byte, driver_byte; |
| 2383 | int error_value; | ||
| 2384 | |||
| 2385 | /* If we get in here, it means we got "target status", that is, scsi status */ | ||
| 2386 | status_byte = cmd->err_info->ScsiStatus; | ||
| 2387 | driver_byte = DRIVER_OK; | ||
| 2388 | msg_byte = cmd->err_info->CommandStatus; /* correct? seems too device specific */ | ||
| 2389 | |||
| 2390 | if (blk_pc_request(cmd->rq)) | ||
| 2391 | host_byte = DID_PASSTHROUGH; | ||
| 2392 | else | ||
| 2393 | host_byte = DID_OK; | ||
| 2394 | |||
| 2395 | error_value = make_status_bytes(status_byte, msg_byte, | ||
| 2396 | host_byte, driver_byte); | ||
| 2372 | 2397 | ||
| 2373 | if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ | 2398 | if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) { |
| 2374 | if (!blk_pc_request(cmd->rq)) | 2399 | if (!blk_pc_request(cmd->rq)) |
| 2375 | printk(KERN_WARNING "cciss: cmd %p " | 2400 | printk(KERN_WARNING "cciss: cmd %p " |
| 2376 | "has SCSI Status 0x%x\n", | 2401 | "has SCSI Status 0x%x\n", |
| 2377 | cmd, cmd->err_info->ScsiStatus); | 2402 | cmd, cmd->err_info->ScsiStatus); |
| 2378 | return error_count; | 2403 | return error_value; |
| 2379 | } | 2404 | } |
| 2380 | 2405 | ||
| 2381 | /* check the sense key */ | 2406 | /* check the sense key */ |
| 2382 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; | 2407 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; |
| 2383 | /* no status or recovered error */ | 2408 | /* no status or recovered error */ |
| 2384 | if ((sense_key == 0x0) || (sense_key == 0x1)) | 2409 | if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq)) |
| 2385 | error_count = 0; | 2410 | error_value = 0; |
| 2386 | 2411 | ||
| 2387 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ | 2412 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ |
| 2388 | if (error_count != 0) | 2413 | if (error_value != 0) |
| 2389 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" | 2414 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" |
| 2390 | " sense key = 0x%x\n", cmd, sense_key); | 2415 | " sense key = 0x%x\n", cmd, sense_key); |
| 2391 | return error_count; | 2416 | return error_value; |
| 2392 | } | 2417 | } |
| 2393 | 2418 | ||
| 2394 | /* SG_IO or similar, copy sense data back */ | 2419 | /* SG_IO or similar, copy sense data back */ |
| @@ -2400,7 +2425,7 @@ static inline int evaluate_target_status(CommandList_struct *cmd) | |||
| 2400 | } else | 2425 | } else |
| 2401 | cmd->rq->sense_len = 0; | 2426 | cmd->rq->sense_len = 0; |
| 2402 | 2427 | ||
| 2403 | return error_count; | 2428 | return error_value; |
| 2404 | } | 2429 | } |
| 2405 | 2430 | ||
| 2406 | /* checks the status of the job and calls complete buffers to mark all | 2431 | /* checks the status of the job and calls complete buffers to mark all |
| @@ -2416,7 +2441,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
| 2416 | rq->errors = 0; | 2441 | rq->errors = 0; |
| 2417 | 2442 | ||
| 2418 | if (timeout) | 2443 | if (timeout) |
| 2419 | rq->errors = 1; | 2444 | rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT); |
| 2420 | 2445 | ||
| 2421 | if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ | 2446 | if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ |
| 2422 | goto after_error_processing; | 2447 | goto after_error_processing; |
| @@ -2442,32 +2467,44 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
| 2442 | case CMD_INVALID: | 2467 | case CMD_INVALID: |
| 2443 | printk(KERN_WARNING "cciss: cmd %p is " | 2468 | printk(KERN_WARNING "cciss: cmd %p is " |
| 2444 | "reported invalid\n", cmd); | 2469 | "reported invalid\n", cmd); |
| 2445 | rq->errors = 1; | 2470 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2471 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2472 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2446 | break; | 2473 | break; |
| 2447 | case CMD_PROTOCOL_ERR: | 2474 | case CMD_PROTOCOL_ERR: |
| 2448 | printk(KERN_WARNING "cciss: cmd %p has " | 2475 | printk(KERN_WARNING "cciss: cmd %p has " |
| 2449 | "protocol error \n", cmd); | 2476 | "protocol error \n", cmd); |
| 2450 | rq->errors = 1; | 2477 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2478 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2479 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2451 | break; | 2480 | break; |
| 2452 | case CMD_HARDWARE_ERR: | 2481 | case CMD_HARDWARE_ERR: |
| 2453 | printk(KERN_WARNING "cciss: cmd %p had " | 2482 | printk(KERN_WARNING "cciss: cmd %p had " |
| 2454 | " hardware error\n", cmd); | 2483 | " hardware error\n", cmd); |
| 2455 | rq->errors = 1; | 2484 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2485 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2486 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2456 | break; | 2487 | break; |
| 2457 | case CMD_CONNECTION_LOST: | 2488 | case CMD_CONNECTION_LOST: |
| 2458 | printk(KERN_WARNING "cciss: cmd %p had " | 2489 | printk(KERN_WARNING "cciss: cmd %p had " |
| 2459 | "connection lost\n", cmd); | 2490 | "connection lost\n", cmd); |
| 2460 | rq->errors = 1; | 2491 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2492 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2493 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2461 | break; | 2494 | break; |
| 2462 | case CMD_ABORTED: | 2495 | case CMD_ABORTED: |
| 2463 | printk(KERN_WARNING "cciss: cmd %p was " | 2496 | printk(KERN_WARNING "cciss: cmd %p was " |
| 2464 | "aborted\n", cmd); | 2497 | "aborted\n", cmd); |
| 2465 | rq->errors = 1; | 2498 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2499 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2500 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); | ||
| 2466 | break; | 2501 | break; |
| 2467 | case CMD_ABORT_FAILED: | 2502 | case CMD_ABORT_FAILED: |
| 2468 | printk(KERN_WARNING "cciss: cmd %p reports " | 2503 | printk(KERN_WARNING "cciss: cmd %p reports " |
| 2469 | "abort failed\n", cmd); | 2504 | "abort failed\n", cmd); |
| 2470 | rq->errors = 1; | 2505 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2506 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2507 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2471 | break; | 2508 | break; |
| 2472 | case CMD_UNSOLICITED_ABORT: | 2509 | case CMD_UNSOLICITED_ABORT: |
| 2473 | printk(KERN_WARNING "cciss%d: unsolicited " | 2510 | printk(KERN_WARNING "cciss%d: unsolicited " |
| @@ -2481,17 +2518,23 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
| 2481 | printk(KERN_WARNING | 2518 | printk(KERN_WARNING |
| 2482 | "cciss%d: %p retried too " | 2519 | "cciss%d: %p retried too " |
| 2483 | "many times\n", h->ctlr, cmd); | 2520 | "many times\n", h->ctlr, cmd); |
| 2484 | rq->errors = 1; | 2521 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2522 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2523 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); | ||
| 2485 | break; | 2524 | break; |
| 2486 | case CMD_TIMEOUT: | 2525 | case CMD_TIMEOUT: |
| 2487 | printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); | 2526 | printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); |
| 2488 | rq->errors = 1; | 2527 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2528 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2529 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2489 | break; | 2530 | break; |
| 2490 | default: | 2531 | default: |
| 2491 | printk(KERN_WARNING "cciss: cmd %p returned " | 2532 | printk(KERN_WARNING "cciss: cmd %p returned " |
| 2492 | "unknown status %x\n", cmd, | 2533 | "unknown status %x\n", cmd, |
| 2493 | cmd->err_info->CommandStatus); | 2534 | cmd->err_info->CommandStatus); |
| 2494 | rq->errors = 1; | 2535 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
| 2536 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
| 2537 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
| 2495 | } | 2538 | } |
| 2496 | 2539 | ||
| 2497 | after_error_processing: | 2540 | after_error_processing: |
