diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/block/cciss.c | 88 | ||||
| -rw-r--r-- | drivers/block/cciss.h | 2 | ||||
| -rw-r--r-- | drivers/block/cciss_cmd.h | 23 |
3 files changed, 111 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 | ||
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 15e2b84734e3..703e08038fb9 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h | |||
| @@ -121,6 +121,8 @@ struct ctlr_info | |||
| 121 | struct sendcmd_reject_list scsi_rejects; | 121 | struct sendcmd_reject_list scsi_rejects; |
| 122 | #endif | 122 | #endif |
| 123 | unsigned char alive; | 123 | unsigned char alive; |
| 124 | struct completion *rescan_wait; | ||
| 125 | struct task_struct *cciss_scan_thread; | ||
| 124 | }; | 126 | }; |
| 125 | 127 | ||
| 126 | /* Defining the diffent access_menthods */ | 128 | /* Defining the diffent access_menthods */ |
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 24e22dea1a99..40b1b92dae7f 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h | |||
| @@ -25,6 +25,29 @@ | |||
| 25 | #define CMD_TIMEOUT 0x000B | 25 | #define CMD_TIMEOUT 0x000B |
| 26 | #define CMD_UNABORTABLE 0x000C | 26 | #define CMD_UNABORTABLE 0x000C |
| 27 | 27 | ||
| 28 | /* Unit Attentions ASC's as defined for the MSA2012sa */ | ||
| 29 | #define POWER_OR_RESET 0x29 | ||
| 30 | #define STATE_CHANGED 0x2a | ||
| 31 | #define UNIT_ATTENTION_CLEARED 0x2f | ||
| 32 | #define LUN_FAILED 0x3e | ||
| 33 | #define REPORT_LUNS_CHANGED 0x3f | ||
| 34 | |||
| 35 | /* Unit Attentions ASCQ's as defined for the MSA2012sa */ | ||
| 36 | |||
| 37 | /* These ASCQ's defined for ASC = POWER_OR_RESET */ | ||
| 38 | #define POWER_ON_RESET 0x00 | ||
| 39 | #define POWER_ON_REBOOT 0x01 | ||
| 40 | #define SCSI_BUS_RESET 0x02 | ||
| 41 | #define MSA_TARGET_RESET 0x03 | ||
| 42 | #define CONTROLLER_FAILOVER 0x04 | ||
| 43 | #define TRANSCEIVER_SE 0x05 | ||
| 44 | #define TRANSCEIVER_LVD 0x06 | ||
| 45 | |||
| 46 | /* These ASCQ's defined for ASC = STATE_CHANGED */ | ||
| 47 | #define RESERVATION_PREEMPTED 0x03 | ||
| 48 | #define ASYM_ACCESS_CHANGED 0x06 | ||
| 49 | #define LUN_CAPACITY_CHANGED 0x09 | ||
| 50 | |||
| 28 | //transfer direction | 51 | //transfer direction |
| 29 | #define XFER_NONE 0x00 | 52 | #define XFER_NONE 0x00 |
| 30 | #define XFER_WRITE 0x01 | 53 | #define XFER_WRITE 0x01 |
