diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 288 |
1 files changed, 176 insertions, 112 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 65a725cd3422..370dfe1c422e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -45,6 +45,10 @@ | |||
45 | #include <linux/blkdev.h> | 45 | #include <linux/blkdev.h> |
46 | #include <linux/genhd.h> | 46 | #include <linux/genhd.h> |
47 | #include <linux/completion.h> | 47 | #include <linux/completion.h> |
48 | #include <scsi/scsi.h> | ||
49 | #include <scsi/sg.h> | ||
50 | #include <scsi/scsi_ioctl.h> | ||
51 | #include <linux/cdrom.h> | ||
48 | 52 | ||
49 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) | 53 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) |
50 | #define DRIVER_NAME "HP CISS Driver (v 3.6.14)" | 54 | #define DRIVER_NAME "HP CISS Driver (v 3.6.14)" |
@@ -1152,6 +1156,30 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
1152 | kfree(ioc); | 1156 | kfree(ioc); |
1153 | return status; | 1157 | return status; |
1154 | } | 1158 | } |
1159 | |||
1160 | /* scsi_cmd_ioctl handles these, below, though some are not */ | ||
1161 | /* very meaningful for cciss. SG_IO is the main one people want. */ | ||
1162 | |||
1163 | case SG_GET_VERSION_NUM: | ||
1164 | case SG_SET_TIMEOUT: | ||
1165 | case SG_GET_TIMEOUT: | ||
1166 | case SG_GET_RESERVED_SIZE: | ||
1167 | case SG_SET_RESERVED_SIZE: | ||
1168 | case SG_EMULATED_HOST: | ||
1169 | case SG_IO: | ||
1170 | case SCSI_IOCTL_SEND_COMMAND: | ||
1171 | return scsi_cmd_ioctl(filep, disk, cmd, argp); | ||
1172 | |||
1173 | /* scsi_cmd_ioctl would normally handle these, below, but */ | ||
1174 | /* they aren't a good fit for cciss, as CD-ROMs are */ | ||
1175 | /* not supported, and we don't have any bus/target/lun */ | ||
1176 | /* which we present to the kernel. */ | ||
1177 | |||
1178 | case CDROM_SEND_PACKET: | ||
1179 | case CDROMCLOSETRAY: | ||
1180 | case CDROMEJECT: | ||
1181 | case SCSI_IOCTL_GET_IDLUN: | ||
1182 | case SCSI_IOCTL_GET_BUS_NUMBER: | ||
1155 | default: | 1183 | default: |
1156 | return -ENOTTY; | 1184 | return -ENOTTY; |
1157 | } | 1185 | } |
@@ -1234,7 +1262,7 @@ static void cciss_softirq_done(struct request *rq) | |||
1234 | pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); | 1262 | pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); |
1235 | } | 1263 | } |
1236 | 1264 | ||
1237 | complete_buffers(rq->bio, rq->errors); | 1265 | complete_buffers(rq->bio, (rq->errors == 0)); |
1238 | 1266 | ||
1239 | if (blk_fs_request(rq)) { | 1267 | if (blk_fs_request(rq)) { |
1240 | const int rw = rq_data_dir(rq); | 1268 | const int rw = rq_data_dir(rq); |
@@ -1248,7 +1276,7 @@ static void cciss_softirq_done(struct request *rq) | |||
1248 | 1276 | ||
1249 | add_disk_randomness(rq->rq_disk); | 1277 | add_disk_randomness(rq->rq_disk); |
1250 | spin_lock_irqsave(&h->lock, flags); | 1278 | spin_lock_irqsave(&h->lock, flags); |
1251 | end_that_request_last(rq, rq->errors); | 1279 | end_that_request_last(rq, (rq->errors == 0)); |
1252 | cmd_free(h, cmd, 1); | 1280 | cmd_free(h, cmd, 1); |
1253 | cciss_check_queues(h); | 1281 | cciss_check_queues(h); |
1254 | spin_unlock_irqrestore(&h->lock, flags); | 1282 | spin_unlock_irqrestore(&h->lock, flags); |
@@ -2336,6 +2364,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) | |||
2336 | start_io(h); | 2364 | start_io(h); |
2337 | } | 2365 | } |
2338 | 2366 | ||
2367 | static inline int evaluate_target_status(CommandList_struct *cmd) | ||
2368 | { | ||
2369 | unsigned char sense_key; | ||
2370 | int error_count = 1; | ||
2371 | |||
2372 | if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ | ||
2373 | if (!blk_pc_request(cmd->rq)) | ||
2374 | printk(KERN_WARNING "cciss: cmd %p " | ||
2375 | "has SCSI Status 0x%x\n", | ||
2376 | cmd, cmd->err_info->ScsiStatus); | ||
2377 | return error_count; | ||
2378 | } | ||
2379 | |||
2380 | /* check the sense key */ | ||
2381 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; | ||
2382 | /* no status or recovered error */ | ||
2383 | if ((sense_key == 0x0) || (sense_key == 0x1)) | ||
2384 | error_count = 0; | ||
2385 | |||
2386 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ | ||
2387 | if (error_count != 0) | ||
2388 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" | ||
2389 | " sense key = 0x%x\n", cmd, sense_key); | ||
2390 | return error_count; | ||
2391 | } | ||
2392 | |||
2393 | /* SG_IO or similar, copy sense data back */ | ||
2394 | if (cmd->rq->sense) { | ||
2395 | if (cmd->rq->sense_len > cmd->err_info->SenseLen) | ||
2396 | cmd->rq->sense_len = cmd->err_info->SenseLen; | ||
2397 | memcpy(cmd->rq->sense, cmd->err_info->SenseInfo, | ||
2398 | cmd->rq->sense_len); | ||
2399 | } else | ||
2400 | cmd->rq->sense_len = 0; | ||
2401 | |||
2402 | return error_count; | ||
2403 | } | ||
2404 | |||
2339 | /* checks the status of the job and calls complete buffers to mark all | 2405 | /* checks the status of the job and calls complete buffers to mark all |
2340 | * buffers for the completed job. Note that this function does not need | 2406 | * buffers for the completed job. Note that this function does not need |
2341 | * to hold the hba/queue lock. | 2407 | * to hold the hba/queue lock. |
@@ -2343,109 +2409,99 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) | |||
2343 | static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | 2409 | static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, |
2344 | int timeout) | 2410 | int timeout) |
2345 | { | 2411 | { |
2346 | int status = 1; | ||
2347 | int retry_cmd = 0; | 2412 | int retry_cmd = 0; |
2413 | struct request *rq = cmd->rq; | ||
2414 | |||
2415 | rq->errors = 0; | ||
2348 | 2416 | ||
2349 | if (timeout) | 2417 | if (timeout) |
2350 | status = 0; | 2418 | rq->errors = 1; |
2351 | 2419 | ||
2352 | if (cmd->err_info->CommandStatus != 0) { /* an error has occurred */ | 2420 | if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ |
2353 | switch (cmd->err_info->CommandStatus) { | 2421 | goto after_error_processing; |
2354 | unsigned char sense_key; | ||
2355 | case CMD_TARGET_STATUS: | ||
2356 | status = 0; | ||
2357 | 2422 | ||
2358 | if (cmd->err_info->ScsiStatus == 0x02) { | 2423 | switch (cmd->err_info->CommandStatus) { |
2359 | printk(KERN_WARNING "cciss: cmd %p " | 2424 | case CMD_TARGET_STATUS: |
2360 | "has CHECK CONDITION " | 2425 | rq->errors = evaluate_target_status(cmd); |
2361 | " byte 2 = 0x%x\n", cmd, | 2426 | break; |
2362 | cmd->err_info->SenseInfo[2] | 2427 | case CMD_DATA_UNDERRUN: |
2363 | ); | 2428 | if (blk_fs_request(cmd->rq)) { |
2364 | /* check the sense key */ | ||
2365 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; | ||
2366 | /* no status or recovered error */ | ||
2367 | if ((sense_key == 0x0) || (sense_key == 0x1)) { | ||
2368 | status = 1; | ||
2369 | } | ||
2370 | } else { | ||
2371 | printk(KERN_WARNING "cciss: cmd %p " | ||
2372 | "has SCSI Status 0x%x\n", | ||
2373 | cmd, cmd->err_info->ScsiStatus); | ||
2374 | } | ||
2375 | break; | ||
2376 | case CMD_DATA_UNDERRUN: | ||
2377 | printk(KERN_WARNING "cciss: cmd %p has" | 2429 | printk(KERN_WARNING "cciss: cmd %p has" |
2378 | " completed with data underrun " | 2430 | " completed with data underrun " |
2379 | "reported\n", cmd); | 2431 | "reported\n", cmd); |
2380 | break; | 2432 | cmd->rq->data_len = cmd->err_info->ResidualCnt; |
2381 | case CMD_DATA_OVERRUN: | 2433 | } |
2434 | break; | ||
2435 | case CMD_DATA_OVERRUN: | ||
2436 | if (blk_fs_request(cmd->rq)) | ||
2382 | printk(KERN_WARNING "cciss: cmd %p has" | 2437 | printk(KERN_WARNING "cciss: cmd %p has" |
2383 | " completed with data overrun " | 2438 | " completed with data overrun " |
2384 | "reported\n", cmd); | 2439 | "reported\n", cmd); |
2385 | break; | 2440 | break; |
2386 | case CMD_INVALID: | 2441 | case CMD_INVALID: |
2387 | printk(KERN_WARNING "cciss: cmd %p is " | 2442 | printk(KERN_WARNING "cciss: cmd %p is " |
2388 | "reported invalid\n", cmd); | 2443 | "reported invalid\n", cmd); |
2389 | status = 0; | 2444 | rq->errors = 1; |
2390 | break; | 2445 | break; |
2391 | case CMD_PROTOCOL_ERR: | 2446 | case CMD_PROTOCOL_ERR: |
2392 | printk(KERN_WARNING "cciss: cmd %p has " | 2447 | printk(KERN_WARNING "cciss: cmd %p has " |
2393 | "protocol error \n", cmd); | 2448 | "protocol error \n", cmd); |
2394 | status = 0; | 2449 | rq->errors = 1; |
2395 | break; | 2450 | break; |
2396 | case CMD_HARDWARE_ERR: | 2451 | case CMD_HARDWARE_ERR: |
2397 | printk(KERN_WARNING "cciss: cmd %p had " | 2452 | printk(KERN_WARNING "cciss: cmd %p had " |
2398 | " hardware error\n", cmd); | 2453 | " hardware error\n", cmd); |
2399 | status = 0; | 2454 | rq->errors = 1; |
2400 | break; | 2455 | break; |
2401 | case CMD_CONNECTION_LOST: | 2456 | case CMD_CONNECTION_LOST: |
2402 | printk(KERN_WARNING "cciss: cmd %p had " | 2457 | printk(KERN_WARNING "cciss: cmd %p had " |
2403 | "connection lost\n", cmd); | 2458 | "connection lost\n", cmd); |
2404 | status = 0; | 2459 | rq->errors = 1; |
2405 | break; | 2460 | break; |
2406 | case CMD_ABORTED: | 2461 | case CMD_ABORTED: |
2407 | printk(KERN_WARNING "cciss: cmd %p was " | 2462 | printk(KERN_WARNING "cciss: cmd %p was " |
2408 | "aborted\n", cmd); | 2463 | "aborted\n", cmd); |
2409 | status = 0; | 2464 | rq->errors = 1; |
2410 | break; | 2465 | break; |
2411 | case CMD_ABORT_FAILED: | 2466 | case CMD_ABORT_FAILED: |
2412 | printk(KERN_WARNING "cciss: cmd %p reports " | 2467 | printk(KERN_WARNING "cciss: cmd %p reports " |
2413 | "abort failed\n", cmd); | 2468 | "abort failed\n", cmd); |
2414 | status = 0; | 2469 | rq->errors = 1; |
2415 | break; | 2470 | break; |
2416 | case CMD_UNSOLICITED_ABORT: | 2471 | case CMD_UNSOLICITED_ABORT: |
2417 | printk(KERN_WARNING "cciss%d: unsolicited " | 2472 | printk(KERN_WARNING "cciss%d: unsolicited " |
2418 | "abort %p\n", h->ctlr, cmd); | 2473 | "abort %p\n", h->ctlr, cmd); |
2419 | if (cmd->retry_count < MAX_CMD_RETRIES) { | 2474 | if (cmd->retry_count < MAX_CMD_RETRIES) { |
2420 | retry_cmd = 1; | 2475 | retry_cmd = 1; |
2421 | printk(KERN_WARNING | 2476 | printk(KERN_WARNING |
2422 | "cciss%d: retrying %p\n", h->ctlr, cmd); | 2477 | "cciss%d: retrying %p\n", h->ctlr, cmd); |
2423 | cmd->retry_count++; | 2478 | cmd->retry_count++; |
2424 | } else | 2479 | } else |
2425 | printk(KERN_WARNING | 2480 | printk(KERN_WARNING |
2426 | "cciss%d: %p retried too " | 2481 | "cciss%d: %p retried too " |
2427 | "many times\n", h->ctlr, cmd); | 2482 | "many times\n", h->ctlr, cmd); |
2428 | status = 0; | 2483 | rq->errors = 1; |
2429 | break; | 2484 | break; |
2430 | case CMD_TIMEOUT: | 2485 | case CMD_TIMEOUT: |
2431 | printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); | 2486 | printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); |
2432 | status = 0; | 2487 | rq->errors = 1; |
2433 | break; | 2488 | break; |
2434 | default: | 2489 | default: |
2435 | printk(KERN_WARNING "cciss: cmd %p returned " | 2490 | printk(KERN_WARNING "cciss: cmd %p returned " |
2436 | "unknown status %x\n", cmd, | 2491 | "unknown status %x\n", cmd, |
2437 | cmd->err_info->CommandStatus); | 2492 | cmd->err_info->CommandStatus); |
2438 | status = 0; | 2493 | rq->errors = 1; |
2439 | } | ||
2440 | } | 2494 | } |
2495 | |||
2496 | after_error_processing: | ||
2497 | |||
2441 | /* We need to return this command */ | 2498 | /* We need to return this command */ |
2442 | if (retry_cmd) { | 2499 | if (retry_cmd) { |
2443 | resend_cciss_cmd(h, cmd); | 2500 | resend_cciss_cmd(h, cmd); |
2444 | return; | 2501 | return; |
2445 | } | 2502 | } |
2446 | 2503 | cmd->rq->data_len = 0; | |
2447 | cmd->rq->completion_data = cmd; | 2504 | cmd->rq->completion_data = cmd; |
2448 | cmd->rq->errors = status; | ||
2449 | blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); | 2505 | blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); |
2450 | blk_complete_request(cmd->rq); | 2506 | blk_complete_request(cmd->rq); |
2451 | } | 2507 | } |
@@ -2539,32 +2595,40 @@ static void do_cciss_request(request_queue_t *q) | |||
2539 | #endif /* CCISS_DEBUG */ | 2595 | #endif /* CCISS_DEBUG */ |
2540 | 2596 | ||
2541 | c->Header.SGList = c->Header.SGTotal = seg; | 2597 | c->Header.SGList = c->Header.SGTotal = seg; |
2542 | if(h->cciss_read == CCISS_READ_10) { | 2598 | if (likely(blk_fs_request(creq))) { |
2543 | c->Request.CDB[1] = 0; | 2599 | if(h->cciss_read == CCISS_READ_10) { |
2544 | c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB | 2600 | c->Request.CDB[1] = 0; |
2545 | c->Request.CDB[3] = (start_blk >> 16) & 0xff; | 2601 | c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB |
2546 | c->Request.CDB[4] = (start_blk >> 8) & 0xff; | 2602 | c->Request.CDB[3] = (start_blk >> 16) & 0xff; |
2547 | c->Request.CDB[5] = start_blk & 0xff; | 2603 | c->Request.CDB[4] = (start_blk >> 8) & 0xff; |
2548 | c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB | 2604 | c->Request.CDB[5] = start_blk & 0xff; |
2549 | c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; | 2605 | c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB |
2550 | c->Request.CDB[8] = creq->nr_sectors & 0xff; | 2606 | c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; |
2551 | c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; | 2607 | c->Request.CDB[8] = creq->nr_sectors & 0xff; |
2608 | c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; | ||
2609 | } else { | ||
2610 | c->Request.CDBLen = 16; | ||
2611 | c->Request.CDB[1]= 0; | ||
2612 | c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB | ||
2613 | c->Request.CDB[3]= (start_blk >> 48) & 0xff; | ||
2614 | c->Request.CDB[4]= (start_blk >> 40) & 0xff; | ||
2615 | c->Request.CDB[5]= (start_blk >> 32) & 0xff; | ||
2616 | c->Request.CDB[6]= (start_blk >> 24) & 0xff; | ||
2617 | c->Request.CDB[7]= (start_blk >> 16) & 0xff; | ||
2618 | c->Request.CDB[8]= (start_blk >> 8) & 0xff; | ||
2619 | c->Request.CDB[9]= start_blk & 0xff; | ||
2620 | c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; | ||
2621 | c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; | ||
2622 | c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; | ||
2623 | c->Request.CDB[13]= creq->nr_sectors & 0xff; | ||
2624 | c->Request.CDB[14] = c->Request.CDB[15] = 0; | ||
2625 | } | ||
2626 | } else if (blk_pc_request(creq)) { | ||
2627 | c->Request.CDBLen = creq->cmd_len; | ||
2628 | memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB); | ||
2552 | } else { | 2629 | } else { |
2553 | c->Request.CDBLen = 16; | 2630 | printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type); |
2554 | c->Request.CDB[1]= 0; | 2631 | BUG(); |
2555 | c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB | ||
2556 | c->Request.CDB[3]= (start_blk >> 48) & 0xff; | ||
2557 | c->Request.CDB[4]= (start_blk >> 40) & 0xff; | ||
2558 | c->Request.CDB[5]= (start_blk >> 32) & 0xff; | ||
2559 | c->Request.CDB[6]= (start_blk >> 24) & 0xff; | ||
2560 | c->Request.CDB[7]= (start_blk >> 16) & 0xff; | ||
2561 | c->Request.CDB[8]= (start_blk >> 8) & 0xff; | ||
2562 | c->Request.CDB[9]= start_blk & 0xff; | ||
2563 | c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; | ||
2564 | c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; | ||
2565 | c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; | ||
2566 | c->Request.CDB[13]= creq->nr_sectors & 0xff; | ||
2567 | c->Request.CDB[14] = c->Request.CDB[15] = 0; | ||
2568 | } | 2632 | } |
2569 | 2633 | ||
2570 | spin_lock_irq(q->queue_lock); | 2634 | spin_lock_irq(q->queue_lock); |