diff options
Diffstat (limited to 'drivers/scsi/pmcraid.c')
-rw-r--r-- | drivers/scsi/pmcraid.c | 138 |
1 files changed, 117 insertions, 21 deletions
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index ecc45c8b4e6b..300d59f389da 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c | |||
@@ -62,6 +62,7 @@ | |||
62 | static unsigned int pmcraid_debug_log; | 62 | static unsigned int pmcraid_debug_log; |
63 | static unsigned int pmcraid_disable_aen; | 63 | static unsigned int pmcraid_disable_aen; |
64 | static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; | 64 | static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; |
65 | static unsigned int pmcraid_enable_msix; | ||
65 | 66 | ||
66 | /* | 67 | /* |
67 | * Data structures to support multiple adapters by the LLD. | 68 | * Data structures to support multiple adapters by the LLD. |
@@ -1594,10 +1595,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) | |||
1594 | cfg_entry = &ccn_hcam->cfg_entry; | 1595 | cfg_entry = &ccn_hcam->cfg_entry; |
1595 | fw_version = be16_to_cpu(pinstance->inq_data->fw_version); | 1596 | fw_version = be16_to_cpu(pinstance->inq_data->fw_version); |
1596 | 1597 | ||
1597 | pmcraid_info | 1598 | pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ |
1598 | ("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n", | 1599 | res: %x:%x:%x:%x\n", |
1599 | pinstance->ccn.hcam->ilid, | 1600 | pinstance->ccn.hcam->ilid, |
1600 | pinstance->ccn.hcam->op_code, | 1601 | pinstance->ccn.hcam->op_code, |
1602 | ((pinstance->ccn.hcam->timestamp1) | | ||
1603 | ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)), | ||
1601 | pinstance->ccn.hcam->notification_type, | 1604 | pinstance->ccn.hcam->notification_type, |
1602 | pinstance->ccn.hcam->notification_lost, | 1605 | pinstance->ccn.hcam->notification_lost, |
1603 | pinstance->ccn.hcam->flags, | 1606 | pinstance->ccn.hcam->flags, |
@@ -1850,6 +1853,7 @@ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) | |||
1850 | * none | 1853 | * none |
1851 | */ | 1854 | */ |
1852 | static void pmcraid_initiate_reset(struct pmcraid_instance *); | 1855 | static void pmcraid_initiate_reset(struct pmcraid_instance *); |
1856 | static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); | ||
1853 | 1857 | ||
1854 | static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) | 1858 | static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) |
1855 | { | 1859 | { |
@@ -1881,6 +1885,10 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) | |||
1881 | lock_flags); | 1885 | lock_flags); |
1882 | return; | 1886 | return; |
1883 | } | 1887 | } |
1888 | if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) { | ||
1889 | pinstance->timestamp_error = 1; | ||
1890 | pmcraid_set_timestamp(cmd); | ||
1891 | } | ||
1884 | } else { | 1892 | } else { |
1885 | dev_info(&pinstance->pdev->dev, | 1893 | dev_info(&pinstance->pdev->dev, |
1886 | "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); | 1894 | "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); |
@@ -3363,7 +3371,7 @@ static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) | |||
3363 | sg_size = buflen; | 3371 | sg_size = buflen; |
3364 | 3372 | ||
3365 | for (i = 0; i < num_elem; i++) { | 3373 | for (i = 0; i < num_elem; i++) { |
3366 | page = alloc_pages(GFP_KERNEL|GFP_DMA, order); | 3374 | page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order); |
3367 | if (!page) { | 3375 | if (!page) { |
3368 | for (j = i - 1; j >= 0; j--) | 3376 | for (j = i - 1; j >= 0; j--) |
3369 | __free_pages(sg_page(&scatterlist[j]), order); | 3377 | __free_pages(sg_page(&scatterlist[j]), order); |
@@ -3471,7 +3479,7 @@ static int pmcraid_copy_sglist( | |||
3471 | * SCSI_MLQUEUE_DEVICE_BUSY if device is busy | 3479 | * SCSI_MLQUEUE_DEVICE_BUSY if device is busy |
3472 | * SCSI_MLQUEUE_HOST_BUSY if host is busy | 3480 | * SCSI_MLQUEUE_HOST_BUSY if host is busy |
3473 | */ | 3481 | */ |
3474 | static int pmcraid_queuecommand( | 3482 | static int pmcraid_queuecommand_lck( |
3475 | struct scsi_cmnd *scsi_cmd, | 3483 | struct scsi_cmnd *scsi_cmd, |
3476 | void (*done) (struct scsi_cmnd *) | 3484 | void (*done) (struct scsi_cmnd *) |
3477 | ) | 3485 | ) |
@@ -3577,6 +3585,8 @@ static int pmcraid_queuecommand( | |||
3577 | return rc; | 3585 | return rc; |
3578 | } | 3586 | } |
3579 | 3587 | ||
3588 | static DEF_SCSI_QCMD(pmcraid_queuecommand) | ||
3589 | |||
3580 | /** | 3590 | /** |
3581 | * pmcraid_open -char node "open" entry, allowed only users with admin access | 3591 | * pmcraid_open -char node "open" entry, allowed only users with admin access |
3582 | */ | 3592 | */ |
@@ -3739,6 +3749,7 @@ static long pmcraid_ioctl_passthrough( | |||
3739 | unsigned long request_buffer; | 3749 | unsigned long request_buffer; |
3740 | unsigned long request_offset; | 3750 | unsigned long request_offset; |
3741 | unsigned long lock_flags; | 3751 | unsigned long lock_flags; |
3752 | void *ioasa; | ||
3742 | u32 ioasc; | 3753 | u32 ioasc; |
3743 | int request_size; | 3754 | int request_size; |
3744 | int buffer_size; | 3755 | int buffer_size; |
@@ -3780,6 +3791,11 @@ static long pmcraid_ioctl_passthrough( | |||
3780 | rc = __copy_from_user(buffer, | 3791 | rc = __copy_from_user(buffer, |
3781 | (struct pmcraid_passthrough_ioctl_buffer *) arg, | 3792 | (struct pmcraid_passthrough_ioctl_buffer *) arg, |
3782 | sizeof(struct pmcraid_passthrough_ioctl_buffer)); | 3793 | sizeof(struct pmcraid_passthrough_ioctl_buffer)); |
3794 | |||
3795 | ioasa = | ||
3796 | (void *)(arg + | ||
3797 | offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); | ||
3798 | |||
3783 | if (rc) { | 3799 | if (rc) { |
3784 | pmcraid_err("ioctl: can't copy passthrough buffer\n"); | 3800 | pmcraid_err("ioctl: can't copy passthrough buffer\n"); |
3785 | rc = -EFAULT; | 3801 | rc = -EFAULT; |
@@ -3947,22 +3963,14 @@ static long pmcraid_ioctl_passthrough( | |||
3947 | } | 3963 | } |
3948 | 3964 | ||
3949 | out_handle_response: | 3965 | out_handle_response: |
3950 | /* If the command failed for any reason, copy entire IOASA buffer and | 3966 | /* copy entire IOASA buffer and return IOCTL success. |
3951 | * return IOCTL success. If copying IOASA to user-buffer fails, return | 3967 | * If copying IOASA to user-buffer fails, return |
3952 | * EFAULT | 3968 | * EFAULT |
3953 | */ | 3969 | */ |
3954 | if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) { | 3970 | if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, |
3955 | void *ioasa = | 3971 | sizeof(struct pmcraid_ioasa))) { |
3956 | (void *)(arg + | 3972 | pmcraid_err("failed to copy ioasa buffer to user\n"); |
3957 | offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); | 3973 | rc = -EFAULT; |
3958 | |||
3959 | pmcraid_info("command failed with %x\n", | ||
3960 | le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); | ||
3961 | if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, | ||
3962 | sizeof(struct pmcraid_ioasa))) { | ||
3963 | pmcraid_err("failed to copy ioasa buffer to user\n"); | ||
3964 | rc = -EFAULT; | ||
3965 | } | ||
3966 | } | 3974 | } |
3967 | 3975 | ||
3968 | /* If the data transfer was from device, copy the data onto user | 3976 | /* If the data transfer was from device, copy the data onto user |
@@ -4165,6 +4173,7 @@ static const struct file_operations pmcraid_fops = { | |||
4165 | #ifdef CONFIG_COMPAT | 4173 | #ifdef CONFIG_COMPAT |
4166 | .compat_ioctl = pmcraid_chr_ioctl, | 4174 | .compat_ioctl = pmcraid_chr_ioctl, |
4167 | #endif | 4175 | #endif |
4176 | .llseek = noop_llseek, | ||
4168 | }; | 4177 | }; |
4169 | 4178 | ||
4170 | 4179 | ||
@@ -4683,7 +4692,8 @@ pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) | |||
4683 | int rc; | 4692 | int rc; |
4684 | struct pci_dev *pdev = pinstance->pdev; | 4693 | struct pci_dev *pdev = pinstance->pdev; |
4685 | 4694 | ||
4686 | if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { | 4695 | if ((pmcraid_enable_msix) && |
4696 | (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { | ||
4687 | int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; | 4697 | int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; |
4688 | struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; | 4698 | struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; |
4689 | int i; | 4699 | int i; |
@@ -5146,6 +5156,16 @@ static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) | |||
5146 | pinstance->inq_data = NULL; | 5156 | pinstance->inq_data = NULL; |
5147 | pinstance->inq_data_baddr = 0; | 5157 | pinstance->inq_data_baddr = 0; |
5148 | } | 5158 | } |
5159 | |||
5160 | if (pinstance->timestamp_data != NULL) { | ||
5161 | pci_free_consistent(pinstance->pdev, | ||
5162 | sizeof(struct pmcraid_timestamp_data), | ||
5163 | pinstance->timestamp_data, | ||
5164 | pinstance->timestamp_data_baddr); | ||
5165 | |||
5166 | pinstance->timestamp_data = NULL; | ||
5167 | pinstance->timestamp_data_baddr = 0; | ||
5168 | } | ||
5149 | } | 5169 | } |
5150 | 5170 | ||
5151 | /** | 5171 | /** |
@@ -5204,6 +5224,20 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) | |||
5204 | return -ENOMEM; | 5224 | return -ENOMEM; |
5205 | } | 5225 | } |
5206 | 5226 | ||
5227 | /* allocate DMAable memory for set timestamp data buffer */ | ||
5228 | pinstance->timestamp_data = pci_alloc_consistent( | ||
5229 | pinstance->pdev, | ||
5230 | sizeof(struct pmcraid_timestamp_data), | ||
5231 | &pinstance->timestamp_data_baddr); | ||
5232 | |||
5233 | if (pinstance->timestamp_data == NULL) { | ||
5234 | pmcraid_err("couldn't allocate DMA memory for \ | ||
5235 | set time_stamp \n"); | ||
5236 | pmcraid_release_buffers(pinstance); | ||
5237 | return -ENOMEM; | ||
5238 | } | ||
5239 | |||
5240 | |||
5207 | /* Initialize all the command blocks and add them to free pool. No | 5241 | /* Initialize all the command blocks and add them to free pool. No |
5208 | * need to lock (free_pool_lock) as this is done in initialization | 5242 | * need to lock (free_pool_lock) as this is done in initialization |
5209 | * itself | 5243 | * itself |
@@ -5609,6 +5643,68 @@ static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) | |||
5609 | } | 5643 | } |
5610 | 5644 | ||
5611 | /** | 5645 | /** |
5646 | * pmcraid_set_timestamp - set the timestamp to IOAFP | ||
5647 | * | ||
5648 | * @cmd: pointer to pmcraid_cmd structure | ||
5649 | * | ||
5650 | * Return Value | ||
5651 | * 0 for success or non-zero for failure cases | ||
5652 | */ | ||
5653 | static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) | ||
5654 | { | ||
5655 | struct pmcraid_instance *pinstance = cmd->drv_inst; | ||
5656 | struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; | ||
5657 | __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); | ||
5658 | struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; | ||
5659 | |||
5660 | struct timeval tv; | ||
5661 | __le64 timestamp; | ||
5662 | |||
5663 | do_gettimeofday(&tv); | ||
5664 | timestamp = tv.tv_sec * 1000; | ||
5665 | |||
5666 | pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); | ||
5667 | pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); | ||
5668 | pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16); | ||
5669 | pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24); | ||
5670 | pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32); | ||
5671 | pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40); | ||
5672 | |||
5673 | pmcraid_reinit_cmdblk(cmd); | ||
5674 | ioarcb->request_type = REQ_TYPE_SCSI; | ||
5675 | ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); | ||
5676 | ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP; | ||
5677 | ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION; | ||
5678 | memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len)); | ||
5679 | |||
5680 | ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + | ||
5681 | offsetof(struct pmcraid_ioarcb, | ||
5682 | add_data.u.ioadl[0])); | ||
5683 | ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); | ||
5684 | ioarcb->ioarcb_bus_addr &= ~(0x1FULL); | ||
5685 | |||
5686 | ioarcb->request_flags0 |= NO_LINK_DESCS; | ||
5687 | ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; | ||
5688 | ioarcb->data_transfer_length = | ||
5689 | cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); | ||
5690 | ioadl = &(ioarcb->add_data.u.ioadl[0]); | ||
5691 | ioadl->flags = IOADL_FLAGS_LAST_DESC; | ||
5692 | ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr); | ||
5693 | ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); | ||
5694 | |||
5695 | if (!pinstance->timestamp_error) { | ||
5696 | pinstance->timestamp_error = 0; | ||
5697 | pmcraid_send_cmd(cmd, pmcraid_set_supported_devs, | ||
5698 | PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); | ||
5699 | } else { | ||
5700 | pmcraid_send_cmd(cmd, pmcraid_return_cmd, | ||
5701 | PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); | ||
5702 | return; | ||
5703 | } | ||
5704 | } | ||
5705 | |||
5706 | |||
5707 | /** | ||
5612 | * pmcraid_init_res_table - Initialize the resource table | 5708 | * pmcraid_init_res_table - Initialize the resource table |
5613 | * @cmd: pointer to pmcraid command struct | 5709 | * @cmd: pointer to pmcraid command struct |
5614 | * | 5710 | * |
@@ -5719,7 +5815,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) | |||
5719 | 5815 | ||
5720 | /* release the resource list lock */ | 5816 | /* release the resource list lock */ |
5721 | spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); | 5817 | spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); |
5722 | pmcraid_set_supported_devs(cmd); | 5818 | pmcraid_set_timestamp(cmd); |
5723 | } | 5819 | } |
5724 | 5820 | ||
5725 | /** | 5821 | /** |
@@ -6053,10 +6149,10 @@ out_init: | |||
6053 | static void __exit pmcraid_exit(void) | 6149 | static void __exit pmcraid_exit(void) |
6054 | { | 6150 | { |
6055 | pmcraid_netlink_release(); | 6151 | pmcraid_netlink_release(); |
6056 | class_destroy(pmcraid_class); | ||
6057 | unregister_chrdev_region(MKDEV(pmcraid_major, 0), | 6152 | unregister_chrdev_region(MKDEV(pmcraid_major, 0), |
6058 | PMCRAID_MAX_ADAPTERS); | 6153 | PMCRAID_MAX_ADAPTERS); |
6059 | pci_unregister_driver(&pmcraid_driver); | 6154 | pci_unregister_driver(&pmcraid_driver); |
6155 | class_destroy(pmcraid_class); | ||
6060 | } | 6156 | } |
6061 | 6157 | ||
6062 | module_init(pmcraid_init); | 6158 | module_init(pmcraid_init); |