aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorMike Miller (OS Dev) <mikem@beardog.cca.cpqcorp.net>2007-05-08 03:29:32 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:09 -0400
commit03bbfee58d440f5dc2e880944ab75fc644534794 (patch)
treef336c5bc4e152867246d3ec1080a391f16477041 /drivers/block
parentd38ae168bfde9195466b9d45cb1126a657c10942 (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')
-rw-r--r--drivers/block/cciss.c164
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
2366static 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);