diff options
author | Mike Miller (OS Dev) <mikem@beardog.cca.cpqcorp.net> | 2007-05-08 03:29:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 14:15:09 -0400 |
commit | 03bbfee58d440f5dc2e880944ab75fc644534794 (patch) | |
tree | f336c5bc4e152867246d3ec1080a391f16477041 /drivers/block/cciss.c | |
parent | d38ae168bfde9195466b9d45cb1126a657c10942 (diff) |
cciss: add SG_IO ioctl to cciss
For all of you that think cciss should be a scsi driver here is the patch that
you have been waiting for all these years. This patch actually adds the SG_IO
ioctl to cciss. The primary purpose is for clustering and high-availibilty.
But now anyone can exploit this ioctl in any manner they wish.
Note, SCSI_IOCTL_SEND_COMMAND doesn't work with this patch due to rq->errors
being set incorrectly. Subsequent patch fixes that.
Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
Signed-off-by: Mike Miller <mike.miller@hp.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 164 |
1 files changed, 111 insertions, 53 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index b00be1427c3f..efcc908490df 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -45,6 +45,9 @@ | |||
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/sg.h> | ||
49 | #include <scsi/scsi_ioctl.h> | ||
50 | #include <linux/cdrom.h> | ||
48 | 51 | ||
49 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) | 52 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) |
50 | #define DRIVER_NAME "HP CISS Driver (v 3.6.14)" | 53 | #define DRIVER_NAME "HP CISS Driver (v 3.6.14)" |
@@ -1152,6 +1155,30 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
1152 | kfree(ioc); | 1155 | kfree(ioc); |
1153 | return status; | 1156 | return status; |
1154 | } | 1157 | } |
1158 | |||
1159 | /* scsi_cmd_ioctl handles these, below, though some are not */ | ||
1160 | /* very meaningful for cciss. SG_IO is the main one people want. */ | ||
1161 | |||
1162 | case SG_GET_VERSION_NUM: | ||
1163 | case SG_SET_TIMEOUT: | ||
1164 | case SG_GET_TIMEOUT: | ||
1165 | case SG_GET_RESERVED_SIZE: | ||
1166 | case SG_SET_RESERVED_SIZE: | ||
1167 | case SG_EMULATED_HOST: | ||
1168 | case SG_IO: | ||
1169 | case SCSI_IOCTL_SEND_COMMAND: | ||
1170 | return scsi_cmd_ioctl(filep, disk, cmd, argp); | ||
1171 | |||
1172 | /* scsi_cmd_ioctl would normally handle these, below, but */ | ||
1173 | /* they aren't a good fit for cciss, as CD-ROMs are */ | ||
1174 | /* not supported, and we don't have any bus/target/lun */ | ||
1175 | /* which we present to the kernel. */ | ||
1176 | |||
1177 | case CDROM_SEND_PACKET: | ||
1178 | case CDROMCLOSETRAY: | ||
1179 | case CDROMEJECT: | ||
1180 | case SCSI_IOCTL_GET_IDLUN: | ||
1181 | case SCSI_IOCTL_GET_BUS_NUMBER: | ||
1155 | default: | 1182 | default: |
1156 | return -ENOTTY; | 1183 | return -ENOTTY; |
1157 | } | 1184 | } |
@@ -2336,6 +2363,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) | |||
2336 | start_io(h); | 2363 | start_io(h); |
2337 | } | 2364 | } |
2338 | 2365 | ||
2366 | static inline int evaluate_target_status(CommandList_struct *cmd) | ||
2367 | { | ||
2368 | unsigned char sense_key; | ||
2369 | int status = 0; /* 0 means bad, 1 means good. */ | ||
2370 | |||
2371 | if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ | ||
2372 | if (!blk_pc_request(cmd->rq)) | ||
2373 | printk(KERN_WARNING "cciss: cmd %p " | ||
2374 | "has SCSI Status 0x%x\n", | ||
2375 | cmd, cmd->err_info->ScsiStatus); | ||
2376 | return status; | ||
2377 | } | ||
2378 | |||
2379 | /* check the sense key */ | ||
2380 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; | ||
2381 | /* no status or recovered error */ | ||
2382 | if ((sense_key == 0x0) || (sense_key == 0x1)) | ||
2383 | status = 1; | ||
2384 | |||
2385 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ | ||
2386 | if (status == 0) | ||
2387 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" | ||
2388 | " sense key = 0x%x\n", cmd, sense_key); | ||
2389 | return status; | ||
2390 | } | ||
2391 | |||
2392 | /* SG_IO or similar, copy sense data back */ | ||
2393 | if (cmd->rq->sense) { | ||
2394 | if (cmd->rq->sense_len > cmd->err_info->SenseLen) | ||
2395 | cmd->rq->sense_len = cmd->err_info->SenseLen; | ||
2396 | memcpy(cmd->rq->sense, cmd->err_info->SenseInfo, | ||
2397 | cmd->rq->sense_len); | ||
2398 | } else | ||
2399 | cmd->rq->sense_len = 0; | ||
2400 | |||
2401 | return status; | ||
2402 | } | ||
2403 | |||
2339 | /* checks the status of the job and calls complete buffers to mark all | 2404 | /* 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 | 2405 | * buffers for the completed job. Note that this function does not need |
2341 | * to hold the hba/queue lock. | 2406 | * to hold the hba/queue lock. |
@@ -2353,37 +2418,22 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
2353 | goto after_error_processing; | 2418 | goto after_error_processing; |
2354 | 2419 | ||
2355 | switch (cmd->err_info->CommandStatus) { | 2420 | switch (cmd->err_info->CommandStatus) { |
2356 | unsigned char sense_key; | ||
2357 | case CMD_TARGET_STATUS: | 2421 | case CMD_TARGET_STATUS: |
2358 | status = 0; | 2422 | status = evaluate_target_status(cmd); |
2359 | |||
2360 | if (cmd->err_info->ScsiStatus == 0x02) { | ||
2361 | printk(KERN_WARNING "cciss: cmd %p " | ||
2362 | "has CHECK CONDITION " | ||
2363 | " byte 2 = 0x%x\n", cmd, | ||
2364 | cmd->err_info->SenseInfo[2] | ||
2365 | ); | ||
2366 | /* check the sense key */ | ||
2367 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; | ||
2368 | /* no status or recovered error */ | ||
2369 | if ((sense_key == 0x0) || (sense_key == 0x1)) { | ||
2370 | status = 1; | ||
2371 | } | ||
2372 | } else { | ||
2373 | printk(KERN_WARNING "cciss: cmd %p " | ||
2374 | "has SCSI Status 0x%x\n", | ||
2375 | cmd, cmd->err_info->ScsiStatus); | ||
2376 | } | ||
2377 | break; | 2423 | break; |
2378 | case CMD_DATA_UNDERRUN: | 2424 | case CMD_DATA_UNDERRUN: |
2379 | printk(KERN_WARNING "cciss: cmd %p has" | 2425 | if (blk_fs_request(cmd->rq)) { |
2380 | " completed with data underrun " | 2426 | printk(KERN_WARNING "cciss: cmd %p has" |
2381 | "reported\n", cmd); | 2427 | " completed with data underrun " |
2428 | "reported\n", cmd); | ||
2429 | cmd->rq->data_len = cmd->err_info->ResidualCnt; | ||
2430 | } | ||
2382 | break; | 2431 | break; |
2383 | case CMD_DATA_OVERRUN: | 2432 | case CMD_DATA_OVERRUN: |
2384 | printk(KERN_WARNING "cciss: cmd %p has" | 2433 | if (blk_fs_request(cmd->rq)) |
2385 | " completed with data overrun " | 2434 | printk(KERN_WARNING "cciss: cmd %p has" |
2386 | "reported\n", cmd); | 2435 | " completed with data overrun " |
2436 | "reported\n", cmd); | ||
2387 | break; | 2437 | break; |
2388 | case CMD_INVALID: | 2438 | case CMD_INVALID: |
2389 | printk(KERN_WARNING "cciss: cmd %p is " | 2439 | printk(KERN_WARNING "cciss: cmd %p is " |
@@ -2447,9 +2497,9 @@ after_error_processing: | |||
2447 | resend_cciss_cmd(h, cmd); | 2497 | resend_cciss_cmd(h, cmd); |
2448 | return; | 2498 | return; |
2449 | } | 2499 | } |
2450 | 2500 | cmd->rq->data_len = 0; | |
2451 | cmd->rq->completion_data = cmd; | ||
2452 | cmd->rq->errors = status; | 2501 | cmd->rq->errors = status; |
2502 | cmd->rq->completion_data = cmd; | ||
2453 | blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); | 2503 | blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); |
2454 | blk_complete_request(cmd->rq); | 2504 | blk_complete_request(cmd->rq); |
2455 | } | 2505 | } |
@@ -2543,32 +2593,40 @@ static void do_cciss_request(request_queue_t *q) | |||
2543 | #endif /* CCISS_DEBUG */ | 2593 | #endif /* CCISS_DEBUG */ |
2544 | 2594 | ||
2545 | c->Header.SGList = c->Header.SGTotal = seg; | 2595 | c->Header.SGList = c->Header.SGTotal = seg; |
2546 | if(h->cciss_read == CCISS_READ_10) { | 2596 | if (likely(blk_fs_request(creq))) { |
2547 | c->Request.CDB[1] = 0; | 2597 | if(h->cciss_read == CCISS_READ_10) { |
2548 | c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB | 2598 | c->Request.CDB[1] = 0; |
2549 | c->Request.CDB[3] = (start_blk >> 16) & 0xff; | 2599 | c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB |
2550 | c->Request.CDB[4] = (start_blk >> 8) & 0xff; | 2600 | c->Request.CDB[3] = (start_blk >> 16) & 0xff; |
2551 | c->Request.CDB[5] = start_blk & 0xff; | 2601 | c->Request.CDB[4] = (start_blk >> 8) & 0xff; |
2552 | c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB | 2602 | c->Request.CDB[5] = start_blk & 0xff; |
2553 | c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; | 2603 | c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB |
2554 | c->Request.CDB[8] = creq->nr_sectors & 0xff; | 2604 | c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; |
2555 | c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; | 2605 | c->Request.CDB[8] = creq->nr_sectors & 0xff; |
2606 | c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; | ||
2607 | } else { | ||
2608 | c->Request.CDBLen = 16; | ||
2609 | c->Request.CDB[1]= 0; | ||
2610 | c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB | ||
2611 | c->Request.CDB[3]= (start_blk >> 48) & 0xff; | ||
2612 | c->Request.CDB[4]= (start_blk >> 40) & 0xff; | ||
2613 | c->Request.CDB[5]= (start_blk >> 32) & 0xff; | ||
2614 | c->Request.CDB[6]= (start_blk >> 24) & 0xff; | ||
2615 | c->Request.CDB[7]= (start_blk >> 16) & 0xff; | ||
2616 | c->Request.CDB[8]= (start_blk >> 8) & 0xff; | ||
2617 | c->Request.CDB[9]= start_blk & 0xff; | ||
2618 | c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; | ||
2619 | c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; | ||
2620 | c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; | ||
2621 | c->Request.CDB[13]= creq->nr_sectors & 0xff; | ||
2622 | c->Request.CDB[14] = c->Request.CDB[15] = 0; | ||
2623 | } | ||
2624 | } else if (blk_pc_request(creq)) { | ||
2625 | c->Request.CDBLen = creq->cmd_len; | ||
2626 | memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB); | ||
2556 | } else { | 2627 | } else { |
2557 | c->Request.CDBLen = 16; | 2628 | printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type); |
2558 | c->Request.CDB[1]= 0; | 2629 | BUG(); |
2559 | c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB | ||
2560 | c->Request.CDB[3]= (start_blk >> 48) & 0xff; | ||
2561 | c->Request.CDB[4]= (start_blk >> 40) & 0xff; | ||
2562 | c->Request.CDB[5]= (start_blk >> 32) & 0xff; | ||
2563 | c->Request.CDB[6]= (start_blk >> 24) & 0xff; | ||
2564 | c->Request.CDB[7]= (start_blk >> 16) & 0xff; | ||
2565 | c->Request.CDB[8]= (start_blk >> 8) & 0xff; | ||
2566 | c->Request.CDB[9]= start_blk & 0xff; | ||
2567 | c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; | ||
2568 | c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; | ||
2569 | c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; | ||
2570 | c->Request.CDB[13]= creq->nr_sectors & 0xff; | ||
2571 | c->Request.CDB[14] = c->Request.CDB[15] = 0; | ||
2572 | } | 2630 | } |
2573 | 2631 | ||
2574 | spin_lock_irq(q->queue_lock); | 2632 | spin_lock_irq(q->queue_lock); |