diff options
author | Ching Huang <ching2048@areca.com.tw> | 2014-08-19 03:17:45 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-16 12:40:01 -0400 |
commit | bb263c4ecbb186fe394c6c9acc32d8c59b6a7bdd (patch) | |
tree | dd1841d010aae6c78fd2f13b5f5e3b7b32b23754 /drivers/scsi/arcmsr/arcmsr_attr.c | |
parent | 6e38adfc58406e7ea6f6701c49abaf046ce076a8 (diff) |
arcmsr: fix ioctl data read/write error for adapter type C
Rewrite ioctl entry and its relate function. This patch fix ioctl data
read/write error and change data I/O access from byte to Dword.
Signed-off-by: Ching Huang <ching2048@areca.com.tw>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/arcmsr/arcmsr_attr.c')
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_attr.c | 101 |
1 files changed, 71 insertions, 30 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index acdae33de521..16422adcc531 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c | |||
@@ -70,40 +70,75 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, | |||
70 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | 70 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; |
71 | uint8_t *pQbuffer,*ptmpQbuffer; | 71 | uint8_t *pQbuffer,*ptmpQbuffer; |
72 | int32_t allxfer_len = 0; | 72 | int32_t allxfer_len = 0; |
73 | unsigned long flags; | ||
73 | 74 | ||
74 | if (!capable(CAP_SYS_ADMIN)) | 75 | if (!capable(CAP_SYS_ADMIN)) |
75 | return -EACCES; | 76 | return -EACCES; |
76 | 77 | ||
77 | /* do message unit read. */ | 78 | /* do message unit read. */ |
78 | ptmpQbuffer = (uint8_t *)buf; | 79 | ptmpQbuffer = (uint8_t *)buf; |
79 | while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) | 80 | spin_lock_irqsave(&acb->rqbuffer_lock, flags); |
80 | && (allxfer_len < 1031)) { | 81 | if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) { |
81 | pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; | 82 | pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; |
82 | memcpy(ptmpQbuffer, pQbuffer, 1); | 83 | if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) { |
83 | acb->rqbuf_firstindex++; | 84 | if ((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex) >= 1032) { |
84 | acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; | 85 | memcpy(ptmpQbuffer, pQbuffer, 1032); |
85 | ptmpQbuffer++; | 86 | acb->rqbuf_firstindex += 1032; |
86 | allxfer_len++; | 87 | acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; |
88 | allxfer_len = 1032; | ||
89 | } else { | ||
90 | if (((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex) | ||
91 | + acb->rqbuf_lastindex) > 1032) { | ||
92 | memcpy(ptmpQbuffer, pQbuffer, | ||
93 | ARCMSR_MAX_QBUFFER | ||
94 | - acb->rqbuf_firstindex); | ||
95 | ptmpQbuffer += ARCMSR_MAX_QBUFFER | ||
96 | - acb->rqbuf_firstindex; | ||
97 | memcpy(ptmpQbuffer, acb->rqbuffer, 1032 | ||
98 | - (ARCMSR_MAX_QBUFFER - | ||
99 | acb->rqbuf_firstindex)); | ||
100 | acb->rqbuf_firstindex = 1032 - | ||
101 | (ARCMSR_MAX_QBUFFER - | ||
102 | acb->rqbuf_firstindex); | ||
103 | allxfer_len = 1032; | ||
104 | } else { | ||
105 | memcpy(ptmpQbuffer, pQbuffer, | ||
106 | ARCMSR_MAX_QBUFFER - | ||
107 | acb->rqbuf_firstindex); | ||
108 | ptmpQbuffer += ARCMSR_MAX_QBUFFER - | ||
109 | acb->rqbuf_firstindex; | ||
110 | memcpy(ptmpQbuffer, acb->rqbuffer, | ||
111 | acb->rqbuf_lastindex); | ||
112 | allxfer_len = ARCMSR_MAX_QBUFFER - | ||
113 | acb->rqbuf_firstindex + | ||
114 | acb->rqbuf_lastindex; | ||
115 | acb->rqbuf_firstindex = | ||
116 | acb->rqbuf_lastindex; | ||
117 | } | ||
118 | } | ||
119 | } else { | ||
120 | if ((acb->rqbuf_lastindex - acb->rqbuf_firstindex) > 1032) { | ||
121 | memcpy(ptmpQbuffer, pQbuffer, 1032); | ||
122 | acb->rqbuf_firstindex += 1032; | ||
123 | allxfer_len = 1032; | ||
124 | } else { | ||
125 | memcpy(ptmpQbuffer, pQbuffer, acb->rqbuf_lastindex | ||
126 | - acb->rqbuf_firstindex); | ||
127 | allxfer_len = acb->rqbuf_lastindex - | ||
128 | acb->rqbuf_firstindex; | ||
129 | acb->rqbuf_firstindex = acb->rqbuf_lastindex; | ||
130 | } | ||
131 | } | ||
87 | } | 132 | } |
88 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | 133 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { |
89 | struct QBUFFER __iomem *prbuffer; | 134 | struct QBUFFER __iomem *prbuffer; |
90 | uint8_t __iomem *iop_data; | ||
91 | int32_t iop_len; | ||
92 | |||
93 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | 135 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; |
94 | prbuffer = arcmsr_get_iop_rqbuffer(acb); | 136 | prbuffer = arcmsr_get_iop_rqbuffer(acb); |
95 | iop_data = prbuffer->data; | 137 | if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) |
96 | iop_len = readl(&prbuffer->data_len); | 138 | acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; |
97 | while (iop_len > 0) { | ||
98 | acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); | ||
99 | acb->rqbuf_lastindex++; | ||
100 | acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | ||
101 | iop_data++; | ||
102 | iop_len--; | ||
103 | } | ||
104 | arcmsr_iop_message_read(acb); | ||
105 | } | 139 | } |
106 | return (allxfer_len); | 140 | spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); |
141 | return allxfer_len; | ||
107 | } | 142 | } |
108 | 143 | ||
109 | static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, | 144 | static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, |
@@ -117,6 +152,7 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, | |||
117 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | 152 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; |
118 | int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; | 153 | int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; |
119 | uint8_t *pQbuffer, *ptmpuserbuffer; | 154 | uint8_t *pQbuffer, *ptmpuserbuffer; |
155 | unsigned long flags; | ||
120 | 156 | ||
121 | if (!capable(CAP_SYS_ADMIN)) | 157 | if (!capable(CAP_SYS_ADMIN)) |
122 | return -EACCES; | 158 | return -EACCES; |
@@ -125,18 +161,19 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, | |||
125 | /* do message unit write. */ | 161 | /* do message unit write. */ |
126 | ptmpuserbuffer = (uint8_t *)buf; | 162 | ptmpuserbuffer = (uint8_t *)buf; |
127 | user_len = (int32_t)count; | 163 | user_len = (int32_t)count; |
164 | spin_lock_irqsave(&acb->wqbuffer_lock, flags); | ||
128 | wqbuf_lastindex = acb->wqbuf_lastindex; | 165 | wqbuf_lastindex = acb->wqbuf_lastindex; |
129 | wqbuf_firstindex = acb->wqbuf_firstindex; | 166 | wqbuf_firstindex = acb->wqbuf_firstindex; |
130 | if (wqbuf_lastindex != wqbuf_firstindex) { | 167 | if (wqbuf_lastindex != wqbuf_firstindex) { |
131 | arcmsr_post_ioctldata2iop(acb); | 168 | arcmsr_write_ioctldata2iop(acb); |
169 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); | ||
132 | return 0; /*need retry*/ | 170 | return 0; /*need retry*/ |
133 | } else { | 171 | } else { |
134 | my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) | 172 | my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) |
135 | &(ARCMSR_MAX_QBUFFER - 1); | 173 | &(ARCMSR_MAX_QBUFFER - 1); |
136 | if (my_empty_len >= user_len) { | 174 | if (my_empty_len >= user_len) { |
137 | while (user_len > 0) { | 175 | while (user_len > 0) { |
138 | pQbuffer = | 176 | pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex]; |
139 | &acb->wqbuffer[acb->wqbuf_lastindex]; | ||
140 | memcpy(pQbuffer, ptmpuserbuffer, 1); | 177 | memcpy(pQbuffer, ptmpuserbuffer, 1); |
141 | acb->wqbuf_lastindex++; | 178 | acb->wqbuf_lastindex++; |
142 | acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; | 179 | acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; |
@@ -146,10 +183,12 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, | |||
146 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { | 183 | if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { |
147 | acb->acb_flags &= | 184 | acb->acb_flags &= |
148 | ~ACB_F_MESSAGE_WQBUFFER_CLEARED; | 185 | ~ACB_F_MESSAGE_WQBUFFER_CLEARED; |
149 | arcmsr_post_ioctldata2iop(acb); | 186 | arcmsr_write_ioctldata2iop(acb); |
150 | } | 187 | } |
188 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); | ||
151 | return count; | 189 | return count; |
152 | } else { | 190 | } else { |
191 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); | ||
153 | return 0; /*need retry*/ | 192 | return 0; /*need retry*/ |
154 | } | 193 | } |
155 | } | 194 | } |
@@ -165,22 +204,24 @@ static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, | |||
165 | struct Scsi_Host *host = class_to_shost(dev); | 204 | struct Scsi_Host *host = class_to_shost(dev); |
166 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; | 205 | struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; |
167 | uint8_t *pQbuffer; | 206 | uint8_t *pQbuffer; |
207 | unsigned long flags; | ||
168 | 208 | ||
169 | if (!capable(CAP_SYS_ADMIN)) | 209 | if (!capable(CAP_SYS_ADMIN)) |
170 | return -EACCES; | 210 | return -EACCES; |
171 | 211 | ||
172 | if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { | 212 | arcmsr_clear_iop2drv_rqueue_buffer(acb); |
173 | acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; | ||
174 | arcmsr_iop_message_read(acb); | ||
175 | } | ||
176 | acb->acb_flags |= | 213 | acb->acb_flags |= |
177 | (ACB_F_MESSAGE_WQBUFFER_CLEARED | 214 | (ACB_F_MESSAGE_WQBUFFER_CLEARED |
178 | | ACB_F_MESSAGE_RQBUFFER_CLEARED | 215 | | ACB_F_MESSAGE_RQBUFFER_CLEARED |
179 | | ACB_F_MESSAGE_WQBUFFER_READED); | 216 | | ACB_F_MESSAGE_WQBUFFER_READED); |
217 | spin_lock_irqsave(&acb->rqbuffer_lock, flags); | ||
180 | acb->rqbuf_firstindex = 0; | 218 | acb->rqbuf_firstindex = 0; |
181 | acb->rqbuf_lastindex = 0; | 219 | acb->rqbuf_lastindex = 0; |
220 | spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); | ||
221 | spin_lock_irqsave(&acb->wqbuffer_lock, flags); | ||
182 | acb->wqbuf_firstindex = 0; | 222 | acb->wqbuf_firstindex = 0; |
183 | acb->wqbuf_lastindex = 0; | 223 | acb->wqbuf_lastindex = 0; |
224 | spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); | ||
184 | pQbuffer = acb->rqbuffer; | 225 | pQbuffer = acb->rqbuffer; |
185 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); | 226 | memset(pQbuffer, 0, sizeof (struct QBUFFER)); |
186 | pQbuffer = acb->wqbuffer; | 227 | pQbuffer = acb->wqbuffer; |