diff options
Diffstat (limited to 'arch/ia64/hp/sim/simscsi.c')
-rw-r--r-- | arch/ia64/hp/sim/simscsi.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index 56405dbfd739..a3fe97531134 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c | |||
@@ -205,10 +205,11 @@ simscsi_get_disk_size (int fd) | |||
205 | char buf[512]; | 205 | char buf[512]; |
206 | 206 | ||
207 | /* | 207 | /* |
208 | * This is a bit kludgey: the simulator doesn't provide a direct way of determining | 208 | * This is a bit kludgey: the simulator doesn't provide a |
209 | * the disk size, so we do a binary search, assuming a maximum disk size of 4GB. | 209 | * direct way of determining the disk size, so we do a binary |
210 | * search, assuming a maximum disk size of 128GB. | ||
210 | */ | 211 | */ |
211 | for (bit = (4UL << 30)/512; bit != 0; bit >>= 1) { | 212 | for (bit = (128UL << 30)/512; bit != 0; bit >>= 1) { |
212 | req.addr = __pa(&buf); | 213 | req.addr = __pa(&buf); |
213 | req.len = sizeof(buf); | 214 | req.len = sizeof(buf); |
214 | ia64_ssc(fd, 1, __pa(&req), ((sectors | bit) - 1)*512, SSC_READ); | 215 | ia64_ssc(fd, 1, __pa(&req), ((sectors | bit) - 1)*512, SSC_READ); |
@@ -225,14 +226,33 @@ simscsi_readwrite10 (struct scsi_cmnd *sc, int mode) | |||
225 | { | 226 | { |
226 | unsigned long offset; | 227 | unsigned long offset; |
227 | 228 | ||
228 | offset = ( (sc->cmnd[2] << 24) | (sc->cmnd[3] << 16) | 229 | offset = (((unsigned long)sc->cmnd[2] << 24) |
229 | | (sc->cmnd[4] << 8) | (sc->cmnd[5] << 0))*512; | 230 | | ((unsigned long)sc->cmnd[3] << 16) |
231 | | ((unsigned long)sc->cmnd[4] << 8) | ||
232 | | ((unsigned long)sc->cmnd[5] << 0))*512UL; | ||
230 | if (sc->use_sg > 0) | 233 | if (sc->use_sg > 0) |
231 | simscsi_sg_readwrite(sc, mode, offset); | 234 | simscsi_sg_readwrite(sc, mode, offset); |
232 | else | 235 | else |
233 | simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512); | 236 | simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512); |
234 | } | 237 | } |
235 | 238 | ||
239 | static void simscsi_fillresult(struct scsi_cmnd *sc, char *buf, unsigned len) | ||
240 | { | ||
241 | |||
242 | int scatterlen = sc->use_sg; | ||
243 | struct scatterlist *slp; | ||
244 | |||
245 | if (scatterlen == 0) | ||
246 | memcpy(sc->request_buffer, buf, len); | ||
247 | else for (slp = (struct scatterlist *)sc->buffer; scatterlen-- > 0 && len > 0; slp++) { | ||
248 | unsigned thislen = min(len, slp->length); | ||
249 | |||
250 | memcpy(page_address(slp->page) + slp->offset, buf, thislen); | ||
251 | slp++; | ||
252 | len -= thislen; | ||
253 | } | ||
254 | } | ||
255 | |||
236 | static int | 256 | static int |
237 | simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | 257 | simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) |
238 | { | 258 | { |
@@ -240,6 +260,7 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
240 | char fname[MAX_ROOT_LEN+16]; | 260 | char fname[MAX_ROOT_LEN+16]; |
241 | size_t disk_size; | 261 | size_t disk_size; |
242 | char *buf; | 262 | char *buf; |
263 | char localbuf[36]; | ||
243 | #if DEBUG_SIMSCSI | 264 | #if DEBUG_SIMSCSI |
244 | register long sp asm ("sp"); | 265 | register long sp asm ("sp"); |
245 | 266 | ||
@@ -263,7 +284,7 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
263 | /* disk doesn't exist... */ | 284 | /* disk doesn't exist... */ |
264 | break; | 285 | break; |
265 | } | 286 | } |
266 | buf = sc->request_buffer; | 287 | buf = localbuf; |
267 | buf[0] = 0; /* magnetic disk */ | 288 | buf[0] = 0; /* magnetic disk */ |
268 | buf[1] = 0; /* not a removable medium */ | 289 | buf[1] = 0; /* not a removable medium */ |
269 | buf[2] = 2; /* SCSI-2 compliant device */ | 290 | buf[2] = 2; /* SCSI-2 compliant device */ |
@@ -273,6 +294,7 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
273 | buf[6] = 0; /* reserved */ | 294 | buf[6] = 0; /* reserved */ |
274 | buf[7] = 0; /* various flags */ | 295 | buf[7] = 0; /* various flags */ |
275 | memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28); | 296 | memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28); |
297 | simscsi_fillresult(sc, buf, 36); | ||
276 | sc->result = GOOD; | 298 | sc->result = GOOD; |
277 | break; | 299 | break; |
278 | 300 | ||
@@ -304,16 +326,13 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
304 | simscsi_readwrite10(sc, SSC_WRITE); | 326 | simscsi_readwrite10(sc, SSC_WRITE); |
305 | break; | 327 | break; |
306 | 328 | ||
307 | |||
308 | case READ_CAPACITY: | 329 | case READ_CAPACITY: |
309 | if (desc[target_id] < 0 || sc->request_bufflen < 8) { | 330 | if (desc[target_id] < 0 || sc->request_bufflen < 8) { |
310 | break; | 331 | break; |
311 | } | 332 | } |
312 | buf = sc->request_buffer; | 333 | buf = localbuf; |
313 | |||
314 | disk_size = simscsi_get_disk_size(desc[target_id]); | 334 | disk_size = simscsi_get_disk_size(desc[target_id]); |
315 | 335 | ||
316 | /* pretend to be a 1GB disk (partition table contains real stuff): */ | ||
317 | buf[0] = (disk_size >> 24) & 0xff; | 336 | buf[0] = (disk_size >> 24) & 0xff; |
318 | buf[1] = (disk_size >> 16) & 0xff; | 337 | buf[1] = (disk_size >> 16) & 0xff; |
319 | buf[2] = (disk_size >> 8) & 0xff; | 338 | buf[2] = (disk_size >> 8) & 0xff; |
@@ -323,13 +342,14 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
323 | buf[5] = 0; | 342 | buf[5] = 0; |
324 | buf[6] = 2; | 343 | buf[6] = 2; |
325 | buf[7] = 0; | 344 | buf[7] = 0; |
345 | simscsi_fillresult(sc, buf, 8); | ||
326 | sc->result = GOOD; | 346 | sc->result = GOOD; |
327 | break; | 347 | break; |
328 | 348 | ||
329 | case MODE_SENSE: | 349 | case MODE_SENSE: |
330 | case MODE_SENSE_10: | 350 | case MODE_SENSE_10: |
331 | /* sd.c uses this to determine whether disk does write-caching. */ | 351 | /* sd.c uses this to determine whether disk does write-caching. */ |
332 | memset(sc->request_buffer, 0, 128); | 352 | simscsi_fillresult(sc, (char *)empty_zero_page, sc->request_bufflen); |
333 | sc->result = GOOD; | 353 | sc->result = GOOD; |
334 | break; | 354 | break; |
335 | 355 | ||