diff options
author | Mike Miller <mike.miller@hp.com> | 2009-04-02 15:50:55 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-04-07 02:12:38 -0400 |
commit | 0a9279cc7cbe726e995c44a1acae81d446775816 (patch) | |
tree | 80b7eb06a7629f6e0ab0c865f791b6a421a0ef6e /drivers/block/cciss.c | |
parent | ac44e5b2ed62bf4acf9df84575d3f18c7a6fdf22 (diff) |
cciss: kernel scan thread for MSA2012
The MSA2012 cannot inform the driver of configuration changes since all
management is out of band. This is a departure from any storage we have
supported in the past. We need some way to detect changes on the topology
so we implement this kernel thread. In some instances there's nothing we
can do from the driver (like LUN failure) so just print out a message. In
the case where logical volumes are added or deleted we call
rebuild_lun_table to refresh the driver's view of the world.
Signed-off-by: Mike Miller <mike.miller@hp.com>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 88 |
1 files changed, 86 insertions, 2 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index f15b17708537..4e5441baa49d 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))) { |
@@ -2593,12 +2605,14 @@ static inline unsigned int make_status_bytes(unsigned int scsi_status_byte, | |||
2593 | ((driver_byte & 0xff) << 24); | 2605 | ((driver_byte & 0xff) << 24); |
2594 | } | 2606 | } |
2595 | 2607 | ||
2596 | 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) | ||
2597 | { | 2610 | { |
2598 | unsigned char sense_key; | 2611 | unsigned char sense_key; |
2599 | unsigned char status_byte, msg_byte, host_byte, driver_byte; | 2612 | unsigned char status_byte, msg_byte, host_byte, driver_byte; |
2600 | int error_value; | 2613 | int error_value; |
2601 | 2614 | ||
2615 | *retry_cmd = 0; | ||
2602 | /* 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 */ |
2603 | status_byte = cmd->err_info->ScsiStatus; | 2617 | status_byte = cmd->err_info->ScsiStatus; |
2604 | driver_byte = DRIVER_OK; | 2618 | driver_byte = DRIVER_OK; |
@@ -2626,6 +2640,11 @@ static inline int evaluate_target_status(CommandList_struct *cmd) | |||
2626 | 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)) |
2627 | error_value = 0; | 2641 | error_value = 0; |
2628 | 2642 | ||
2643 | if (check_for_unit_attention(h, cmd)) { | ||
2644 | *retry_cmd = !blk_pc_request(cmd->rq); | ||
2645 | return 0; | ||
2646 | } | ||
2647 | |||
2629 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ | 2648 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ |
2630 | if (error_value != 0) | 2649 | if (error_value != 0) |
2631 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" | 2650 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" |
@@ -2665,7 +2684,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
2665 | 2684 | ||
2666 | switch (cmd->err_info->CommandStatus) { | 2685 | switch (cmd->err_info->CommandStatus) { |
2667 | case CMD_TARGET_STATUS: | 2686 | case CMD_TARGET_STATUS: |
2668 | rq->errors = evaluate_target_status(cmd); | 2687 | rq->errors = evaluate_target_status(h, cmd, &retry_cmd); |
2669 | break; | 2688 | break; |
2670 | case CMD_DATA_UNDERRUN: | 2689 | case CMD_DATA_UNDERRUN: |
2671 | if (blk_fs_request(cmd->rq)) { | 2690 | if (blk_fs_request(cmd->rq)) { |
@@ -3016,6 +3035,63 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id) | |||
3016 | return IRQ_HANDLED; | 3035 | return IRQ_HANDLED; |
3017 | } | 3036 | } |
3018 | 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 | |||
3019 | /* | 3095 | /* |
3020 | * We cannot read the structure directly, for portability we must use | 3096 | * We cannot read the structure directly, for portability we must use |
3021 | * the io functions. | 3097 | * the io functions. |
@@ -3761,6 +3837,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3761 | hba[i]->busy_initializing = 0; | 3837 | hba[i]->busy_initializing = 0; |
3762 | 3838 | ||
3763 | rebuild_lun_table(hba[i], 1); | 3839 | rebuild_lun_table(hba[i], 1); |
3840 | hba[i]->cciss_scan_thread = kthread_run(scan_thread, hba[i], | ||
3841 | "cciss_scan%02d", i); | ||
3842 | if (IS_ERR(hba[i]->cciss_scan_thread)) | ||
3843 | return PTR_ERR(hba[i]->cciss_scan_thread); | ||
3844 | |||
3764 | return 1; | 3845 | return 1; |
3765 | 3846 | ||
3766 | clean4: | 3847 | clean4: |
@@ -3836,6 +3917,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) | |||
3836 | printk(KERN_ERR "cciss: Unable to remove device \n"); | 3917 | printk(KERN_ERR "cciss: Unable to remove device \n"); |
3837 | return; | 3918 | return; |
3838 | } | 3919 | } |
3920 | |||
3839 | tmp_ptr = pci_get_drvdata(pdev); | 3921 | tmp_ptr = pci_get_drvdata(pdev); |
3840 | i = tmp_ptr->ctlr; | 3922 | i = tmp_ptr->ctlr; |
3841 | if (hba[i] == NULL) { | 3923 | if (hba[i] == NULL) { |
@@ -3844,6 +3926,8 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) | |||
3844 | return; | 3926 | return; |
3845 | } | 3927 | } |
3846 | 3928 | ||
3929 | kthread_stop(hba[i]->cciss_scan_thread); | ||
3930 | |||
3847 | remove_proc_entry(hba[i]->devname, proc_cciss); | 3931 | remove_proc_entry(hba[i]->devname, proc_cciss); |
3848 | unregister_blkdev(hba[i]->major, hba[i]->devname); | 3932 | unregister_blkdev(hba[i]->major, hba[i]->devname); |
3849 | 3933 | ||