diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 117 |
1 files changed, 109 insertions, 8 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index a6c55432819b..0ef6f08aa6ea 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <scsi/scsi_ioctl.h> | 51 | #include <scsi/scsi_ioctl.h> |
52 | #include <linux/cdrom.h> | 52 | #include <linux/cdrom.h> |
53 | #include <linux/scatterlist.h> | 53 | #include <linux/scatterlist.h> |
54 | #include <linux/kthread.h> | ||
54 | 55 | ||
55 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) | 56 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) |
56 | #define DRIVER_NAME "HP CISS Driver (v 3.6.20)" | 57 | #define DRIVER_NAME "HP CISS Driver (v 3.6.20)" |
@@ -186,6 +187,8 @@ static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, | |||
186 | __u8 page_code, int cmd_type); | 187 | __u8 page_code, int cmd_type); |
187 | 188 | ||
188 | static void fail_all_cmds(unsigned long ctlr); | 189 | static void fail_all_cmds(unsigned long ctlr); |
190 | static int scan_thread(void *data); | ||
191 | static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c); | ||
189 | 192 | ||
190 | #ifdef CONFIG_PROC_FS | 193 | #ifdef CONFIG_PROC_FS |
191 | static void cciss_procinit(int i); | 194 | static void cciss_procinit(int i); |
@@ -735,6 +738,12 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo) | |||
735 | return 0; | 738 | return 0; |
736 | } | 739 | } |
737 | 740 | ||
741 | static void check_ioctl_unit_attention(ctlr_info_t *host, CommandList_struct *c) | ||
742 | { | ||
743 | if (c->err_info->CommandStatus == CMD_TARGET_STATUS && | ||
744 | c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) | ||
745 | (void)check_for_unit_attention(host, c); | ||
746 | } | ||
738 | /* | 747 | /* |
739 | * ioctl | 748 | * ioctl |
740 | */ | 749 | */ |
@@ -1029,6 +1038,8 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | |||
1029 | iocommand.buf_size, | 1038 | iocommand.buf_size, |
1030 | PCI_DMA_BIDIRECTIONAL); | 1039 | PCI_DMA_BIDIRECTIONAL); |
1031 | 1040 | ||
1041 | check_ioctl_unit_attention(host, c); | ||
1042 | |||
1032 | /* Copy the error information out */ | 1043 | /* Copy the error information out */ |
1033 | iocommand.error_info = *(c->err_info); | 1044 | iocommand.error_info = *(c->err_info); |
1034 | if (copy_to_user | 1045 | if (copy_to_user |
@@ -1180,6 +1191,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, | |||
1180 | (dma_addr_t) temp64.val, buff_size[i], | 1191 | (dma_addr_t) temp64.val, buff_size[i], |
1181 | PCI_DMA_BIDIRECTIONAL); | 1192 | PCI_DMA_BIDIRECTIONAL); |
1182 | } | 1193 | } |
1194 | check_ioctl_unit_attention(host, c); | ||
1183 | /* Copy the error information out */ | 1195 | /* Copy the error information out */ |
1184 | ioc->error_info = *(c->err_info); | 1196 | ioc->error_info = *(c->err_info); |
1185 | if (copy_to_user(argp, ioc, sizeof(*ioc))) { | 1197 | if (copy_to_user(argp, ioc, sizeof(*ioc))) { |
@@ -1287,6 +1299,7 @@ static void cciss_softirq_done(struct request *rq) | |||
1287 | { | 1299 | { |
1288 | CommandList_struct *cmd = rq->completion_data; | 1300 | CommandList_struct *cmd = rq->completion_data; |
1289 | ctlr_info_t *h = hba[cmd->ctlr]; | 1301 | ctlr_info_t *h = hba[cmd->ctlr]; |
1302 | unsigned int nr_bytes; | ||
1290 | unsigned long flags; | 1303 | unsigned long flags; |
1291 | u64bit temp64; | 1304 | u64bit temp64; |
1292 | int i, ddir; | 1305 | int i, ddir; |
@@ -1308,7 +1321,14 @@ static void cciss_softirq_done(struct request *rq) | |||
1308 | printk("Done with %p\n", rq); | 1321 | printk("Done with %p\n", rq); |
1309 | #endif /* CCISS_DEBUG */ | 1322 | #endif /* CCISS_DEBUG */ |
1310 | 1323 | ||
1311 | if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, blk_rq_bytes(rq))) | 1324 | /* |
1325 | * Store the full size and set the residual count for pc requests | ||
1326 | */ | ||
1327 | nr_bytes = blk_rq_bytes(rq); | ||
1328 | if (blk_pc_request(rq)) | ||
1329 | rq->data_len = cmd->err_info->ResidualCnt; | ||
1330 | |||
1331 | if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, nr_bytes)) | ||
1312 | BUG(); | 1332 | BUG(); |
1313 | 1333 | ||
1314 | spin_lock_irqsave(&h->lock, flags); | 1334 | spin_lock_irqsave(&h->lock, flags); |
@@ -2585,12 +2605,14 @@ static inline unsigned int make_status_bytes(unsigned int scsi_status_byte, | |||
2585 | ((driver_byte & 0xff) << 24); | 2605 | ((driver_byte & 0xff) << 24); |
2586 | } | 2606 | } |
2587 | 2607 | ||
2588 | static inline int evaluate_target_status(CommandList_struct *cmd) | 2608 | static inline int evaluate_target_status(ctlr_info_t *h, |
2609 | CommandList_struct *cmd, int *retry_cmd) | ||
2589 | { | 2610 | { |
2590 | unsigned char sense_key; | 2611 | unsigned char sense_key; |
2591 | unsigned char status_byte, msg_byte, host_byte, driver_byte; | 2612 | unsigned char status_byte, msg_byte, host_byte, driver_byte; |
2592 | int error_value; | 2613 | int error_value; |
2593 | 2614 | ||
2615 | *retry_cmd = 0; | ||
2594 | /* If we get in here, it means we got "target status", that is, scsi status */ | 2616 | /* If we get in here, it means we got "target status", that is, scsi status */ |
2595 | status_byte = cmd->err_info->ScsiStatus; | 2617 | status_byte = cmd->err_info->ScsiStatus; |
2596 | driver_byte = DRIVER_OK; | 2618 | driver_byte = DRIVER_OK; |
@@ -2618,6 +2640,11 @@ static inline int evaluate_target_status(CommandList_struct *cmd) | |||
2618 | if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq)) | 2640 | if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq)) |
2619 | error_value = 0; | 2641 | error_value = 0; |
2620 | 2642 | ||
2643 | if (check_for_unit_attention(h, cmd)) { | ||
2644 | *retry_cmd = !blk_pc_request(cmd->rq); | ||
2645 | return 0; | ||
2646 | } | ||
2647 | |||
2621 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ | 2648 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ |
2622 | if (error_value != 0) | 2649 | if (error_value != 0) |
2623 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" | 2650 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" |
@@ -2657,7 +2684,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
2657 | 2684 | ||
2658 | switch (cmd->err_info->CommandStatus) { | 2685 | switch (cmd->err_info->CommandStatus) { |
2659 | case CMD_TARGET_STATUS: | 2686 | case CMD_TARGET_STATUS: |
2660 | rq->errors = evaluate_target_status(cmd); | 2687 | rq->errors = evaluate_target_status(h, cmd, &retry_cmd); |
2661 | break; | 2688 | break; |
2662 | case CMD_DATA_UNDERRUN: | 2689 | case CMD_DATA_UNDERRUN: |
2663 | if (blk_fs_request(cmd->rq)) { | 2690 | if (blk_fs_request(cmd->rq)) { |
@@ -3008,6 +3035,63 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) | |||
3008 | return IRQ_HANDLED; | 3035 | return IRQ_HANDLED; |
3009 | } | 3036 | } |
3010 | 3037 | ||
3038 | static int scan_thread(void *data) | ||
3039 | { | ||
3040 | ctlr_info_t *h = data; | ||
3041 | int rc; | ||
3042 | DECLARE_COMPLETION_ONSTACK(wait); | ||
3043 | h->rescan_wait = &wait; | ||
3044 | |||
3045 | for (;;) { | ||
3046 | rc = wait_for_completion_interruptible(&wait); | ||
3047 | if (kthread_should_stop()) | ||
3048 | break; | ||
3049 | if (!rc) | ||
3050 | rebuild_lun_table(h, 0); | ||
3051 | } | ||
3052 | return 0; | ||
3053 | } | ||
3054 | |||
3055 | static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c) | ||
3056 | { | ||
3057 | if (c->err_info->SenseInfo[2] != UNIT_ATTENTION) | ||
3058 | return 0; | ||
3059 | |||
3060 | switch (c->err_info->SenseInfo[12]) { | ||
3061 | case STATE_CHANGED: | ||
3062 | printk(KERN_WARNING "cciss%d: a state change " | ||
3063 | "detected, command retried\n", h->ctlr); | ||
3064 | return 1; | ||
3065 | break; | ||
3066 | case LUN_FAILED: | ||
3067 | printk(KERN_WARNING "cciss%d: LUN failure " | ||
3068 | "detected, action required\n", h->ctlr); | ||
3069 | return 1; | ||
3070 | break; | ||
3071 | case REPORT_LUNS_CHANGED: | ||
3072 | printk(KERN_WARNING "cciss%d: report LUN data " | ||
3073 | "changed\n", h->ctlr); | ||
3074 | if (h->rescan_wait) | ||
3075 | complete(h->rescan_wait); | ||
3076 | return 1; | ||
3077 | break; | ||
3078 | case POWER_OR_RESET: | ||
3079 | printk(KERN_WARNING "cciss%d: a power on " | ||
3080 | "or device reset detected\n", h->ctlr); | ||
3081 | return 1; | ||
3082 | break; | ||
3083 | case UNIT_ATTENTION_CLEARED: | ||
3084 | printk(KERN_WARNING "cciss%d: unit attention " | ||
3085 | "cleared by another initiator\n", h->ctlr); | ||
3086 | return 1; | ||
3087 | break; | ||
3088 | default: | ||
3089 | printk(KERN_WARNING "cciss%d: unknown " | ||
3090 | "unit attention detected\n", h->ctlr); | ||
3091 | return 1; | ||
3092 | } | ||
3093 | } | ||
3094 | |||
3011 | /* | 3095 | /* |
3012 | * We cannot read the structure directly, for portability we must use | 3096 | * We cannot read the structure directly, for portability we must use |
3013 | * the io functions. | 3097 | * the io functions. |
@@ -3181,12 +3265,21 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) | |||
3181 | */ | 3265 | */ |
3182 | cciss_interrupt_mode(c, pdev, board_id); | 3266 | cciss_interrupt_mode(c, pdev, board_id); |
3183 | 3267 | ||
3184 | /* | 3268 | /* find the memory BAR */ |
3185 | * Memory base addr is first addr , the second points to the config | 3269 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { |
3186 | * table | 3270 | if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) |
3187 | */ | 3271 | break; |
3272 | } | ||
3273 | if (i == DEVICE_COUNT_RESOURCE) { | ||
3274 | printk(KERN_WARNING "cciss: No memory BAR found\n"); | ||
3275 | err = -ENODEV; | ||
3276 | goto err_out_free_res; | ||
3277 | } | ||
3278 | |||
3279 | c->paddr = pci_resource_start(pdev, i); /* addressing mode bits | ||
3280 | * already removed | ||
3281 | */ | ||
3188 | 3282 | ||
3189 | c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */ | ||
3190 | #ifdef CCISS_DEBUG | 3283 | #ifdef CCISS_DEBUG |
3191 | printk("address 0 = %lx\n", c->paddr); | 3284 | printk("address 0 = %lx\n", c->paddr); |
3192 | #endif /* CCISS_DEBUG */ | 3285 | #endif /* CCISS_DEBUG */ |
@@ -3753,6 +3846,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3753 | hba[i]->busy_initializing = 0; | 3846 | hba[i]->busy_initializing = 0; |
3754 | 3847 | ||
3755 | rebuild_lun_table(hba[i], 1); | 3848 | rebuild_lun_table(hba[i], 1); |
3849 | hba[i]->cciss_scan_thread = kthread_run(scan_thread, hba[i], | ||
3850 | "cciss_scan%02d", i); | ||
3851 | if (IS_ERR(hba[i]->cciss_scan_thread)) | ||
3852 | return PTR_ERR(hba[i]->cciss_scan_thread); | ||
3853 | |||
3756 | return 1; | 3854 | return 1; |
3757 | 3855 | ||
3758 | clean4: | 3856 | clean4: |
@@ -3828,6 +3926,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) | |||
3828 | printk(KERN_ERR "cciss: Unable to remove device \n"); | 3926 | printk(KERN_ERR "cciss: Unable to remove device \n"); |
3829 | return; | 3927 | return; |
3830 | } | 3928 | } |
3929 | |||
3831 | tmp_ptr = pci_get_drvdata(pdev); | 3930 | tmp_ptr = pci_get_drvdata(pdev); |
3832 | i = tmp_ptr->ctlr; | 3931 | i = tmp_ptr->ctlr; |
3833 | if (hba[i] == NULL) { | 3932 | if (hba[i] == NULL) { |
@@ -3836,6 +3935,8 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) | |||
3836 | return; | 3935 | return; |
3837 | } | 3936 | } |
3838 | 3937 | ||
3938 | kthread_stop(hba[i]->cciss_scan_thread); | ||
3939 | |||
3839 | remove_proc_entry(hba[i]->devname, proc_cciss); | 3940 | remove_proc_entry(hba[i]->devname, proc_cciss); |
3840 | unregister_blkdev(hba[i]->major, hba[i]->devname); | 3941 | unregister_blkdev(hba[i]->major, hba[i]->devname); |
3841 | 3942 | ||