diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/advansys.c | 105 |
1 files changed, 79 insertions, 26 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index d35897eaa807..88e7fef18a29 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c | |||
@@ -90,17 +90,6 @@ | |||
90 | #define ASC_DCNT __u32 /* Unsigned Data count type. */ | 90 | #define ASC_DCNT __u32 /* Unsigned Data count type. */ |
91 | #define ASC_SDCNT __s32 /* Signed Data count type. */ | 91 | #define ASC_SDCNT __s32 /* Signed Data count type. */ |
92 | 92 | ||
93 | /* | ||
94 | * These macros are used to convert a virtual address to a | ||
95 | * 32-bit value. This currently can be used on Linux Alpha | ||
96 | * which uses 64-bit virtual address but a 32-bit bus address. | ||
97 | * This is likely to break in the future, but doing this now | ||
98 | * will give us time to change the HW and FW to handle 64-bit | ||
99 | * addresses. | ||
100 | */ | ||
101 | #define ASC_VADDR_TO_U32 virt_to_bus | ||
102 | #define ASC_U32_TO_VADDR bus_to_virt | ||
103 | |||
104 | typedef unsigned char uchar; | 93 | typedef unsigned char uchar; |
105 | 94 | ||
106 | #ifndef TRUE | 95 | #ifndef TRUE |
@@ -601,6 +590,8 @@ typedef struct asc_dvc_var { | |||
601 | uchar min_sdtr_index; | 590 | uchar min_sdtr_index; |
602 | uchar max_sdtr_index; | 591 | uchar max_sdtr_index; |
603 | struct asc_board *drv_ptr; | 592 | struct asc_board *drv_ptr; |
593 | int ptr_map_count; | ||
594 | void **ptr_map; | ||
604 | ASC_DCNT uc_break; | 595 | ASC_DCNT uc_break; |
605 | } ASC_DVC_VAR; | 596 | } ASC_DVC_VAR; |
606 | 597 | ||
@@ -2748,6 +2739,59 @@ static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) | |||
2748 | #endif /* ADVANSYS_DEBUG */ | 2739 | #endif /* ADVANSYS_DEBUG */ |
2749 | 2740 | ||
2750 | /* | 2741 | /* |
2742 | * The advansys chip/microcode contains a 32-bit identifier for each command | ||
2743 | * known as the 'srb'. I don't know what it stands for. The driver used | ||
2744 | * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it | ||
2745 | * with bus_to_virt. Now the driver keeps a per-host map of integers to | ||
2746 | * pointers. It auto-expands when full, unless it can't allocate memory. | ||
2747 | * Note that an srb of 0 is treated specially by the chip/firmware, hence | ||
2748 | * the return of i+1 in this routine, and the corresponding subtraction in | ||
2749 | * the inverse routine. | ||
2750 | */ | ||
2751 | #define BAD_SRB 0 | ||
2752 | static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr) | ||
2753 | { | ||
2754 | int i; | ||
2755 | void **new_ptr; | ||
2756 | |||
2757 | for (i = 0; i < asc_dvc->ptr_map_count; i++) { | ||
2758 | if (!asc_dvc->ptr_map[i]) | ||
2759 | goto out; | ||
2760 | } | ||
2761 | |||
2762 | if (asc_dvc->ptr_map_count == 0) | ||
2763 | asc_dvc->ptr_map_count = 1; | ||
2764 | else | ||
2765 | asc_dvc->ptr_map_count *= 2; | ||
2766 | |||
2767 | new_ptr = krealloc(asc_dvc->ptr_map, | ||
2768 | asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC); | ||
2769 | if (!new_ptr) | ||
2770 | return BAD_SRB; | ||
2771 | asc_dvc->ptr_map = new_ptr; | ||
2772 | out: | ||
2773 | ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i); | ||
2774 | asc_dvc->ptr_map[i] = ptr; | ||
2775 | return i + 1; | ||
2776 | } | ||
2777 | |||
2778 | static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb) | ||
2779 | { | ||
2780 | void *ptr; | ||
2781 | |||
2782 | srb--; | ||
2783 | if (srb >= asc_dvc->ptr_map_count) { | ||
2784 | printk("advansys: bad SRB %u, max %u\n", srb, | ||
2785 | asc_dvc->ptr_map_count); | ||
2786 | return NULL; | ||
2787 | } | ||
2788 | ptr = asc_dvc->ptr_map[srb]; | ||
2789 | asc_dvc->ptr_map[srb] = NULL; | ||
2790 | ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb); | ||
2791 | return ptr; | ||
2792 | } | ||
2793 | |||
2794 | /* | ||
2751 | * advansys_info() | 2795 | * advansys_info() |
2752 | * | 2796 | * |
2753 | * Return suitable for printing on the console with the argument | 2797 | * Return suitable for printing on the console with the argument |
@@ -9075,17 +9119,10 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) | |||
9075 | ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep); | 9119 | ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep); |
9076 | ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); | 9120 | ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); |
9077 | 9121 | ||
9078 | /* | 9122 | scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr); |
9079 | * Get the struct scsi_cmnd structure and Scsi_Host structure for the | 9123 | if (!scp) |
9080 | * command that has been completed. | ||
9081 | */ | ||
9082 | scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr); | ||
9083 | ASC_DBG(1, "scp 0x%p\n", scp); | ||
9084 | |||
9085 | if (scp == NULL) { | ||
9086 | ASC_PRINT("asc_isr_callback: scp is NULL\n"); | ||
9087 | return; | 9124 | return; |
9088 | } | 9125 | |
9089 | ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); | 9126 | ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); |
9090 | 9127 | ||
9091 | shost = scp->device->host; | 9128 | shost = scp->device->host; |
@@ -9095,6 +9132,8 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) | |||
9095 | boardp = shost_priv(shost); | 9132 | boardp = shost_priv(shost); |
9096 | BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); | 9133 | BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); |
9097 | 9134 | ||
9135 | dma_unmap_single(boardp->dev, scp->SCp.dma_handle, | ||
9136 | sizeof(scp->sense_buffer), DMA_FROM_DEVICE); | ||
9098 | /* | 9137 | /* |
9099 | * 'qdonep' contains the command's ending status. | 9138 | * 'qdonep' contains the command's ending status. |
9100 | */ | 9139 | */ |
@@ -9835,9 +9874,20 @@ static int advansys_slave_configure(struct scsi_device *sdev) | |||
9835 | return 0; | 9874 | return 0; |
9836 | } | 9875 | } |
9837 | 9876 | ||
9877 | static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp) | ||
9878 | { | ||
9879 | struct asc_board *board = shost_priv(scp->device->host); | ||
9880 | scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer, | ||
9881 | sizeof(scp->sense_buffer), DMA_FROM_DEVICE); | ||
9882 | dma_cache_sync(board->dev, scp->sense_buffer, | ||
9883 | sizeof(scp->sense_buffer), DMA_FROM_DEVICE); | ||
9884 | return cpu_to_le32(scp->SCp.dma_handle); | ||
9885 | } | ||
9886 | |||
9838 | static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, | 9887 | static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, |
9839 | struct asc_scsi_q *asc_scsi_q) | 9888 | struct asc_scsi_q *asc_scsi_q) |
9840 | { | 9889 | { |
9890 | struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var; | ||
9841 | int use_sg; | 9891 | int use_sg; |
9842 | 9892 | ||
9843 | memset(asc_scsi_q, 0, sizeof(*asc_scsi_q)); | 9893 | memset(asc_scsi_q, 0, sizeof(*asc_scsi_q)); |
@@ -9845,7 +9895,11 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, | |||
9845 | /* | 9895 | /* |
9846 | * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. | 9896 | * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. |
9847 | */ | 9897 | */ |
9848 | asc_scsi_q->q2.srb_ptr = ASC_VADDR_TO_U32(scp); | 9898 | asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp); |
9899 | if (asc_scsi_q->q2.srb_ptr == BAD_SRB) { | ||
9900 | scp->result = HOST_BYTE(DID_SOFT_ERROR); | ||
9901 | return ASC_ERROR; | ||
9902 | } | ||
9849 | 9903 | ||
9850 | /* | 9904 | /* |
9851 | * Build the ASC_SCSI_Q request. | 9905 | * Build the ASC_SCSI_Q request. |
@@ -9856,8 +9910,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, | |||
9856 | asc_scsi_q->q1.target_lun = scp->device->lun; | 9910 | asc_scsi_q->q1.target_lun = scp->device->lun; |
9857 | asc_scsi_q->q2.target_ix = | 9911 | asc_scsi_q->q2.target_ix = |
9858 | ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); | 9912 | ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); |
9859 | asc_scsi_q->q1.sense_addr = | 9913 | asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp); |
9860 | cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); | ||
9861 | asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer); | 9914 | asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer); |
9862 | 9915 | ||
9863 | /* | 9916 | /* |
@@ -9871,7 +9924,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, | |||
9871 | * started request. | 9924 | * started request. |
9872 | * | 9925 | * |
9873 | */ | 9926 | */ |
9874 | if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) && | 9927 | if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) && |
9875 | (boardp->reqcnt[scp->device->id] % 255) == 0) { | 9928 | (boardp->reqcnt[scp->device->id] % 255) == 0) { |
9876 | asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG; | 9929 | asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG; |
9877 | } else { | 9930 | } else { |
@@ -10091,7 +10144,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, | |||
10091 | /* | 10144 | /* |
10092 | * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. | 10145 | * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. |
10093 | */ | 10146 | */ |
10094 | scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp); | 10147 | scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp); |
10095 | 10148 | ||
10096 | /* | 10149 | /* |
10097 | * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure. | 10150 | * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure. |