22 |
|
|
23 |
#define DEBUG_ACCESS 0 |
#define DEBUG_ACCESS 0 |
24 |
#define DEBUG_ATA 0 |
#define DEBUG_ATA 0 |
25 |
|
#define DEBUG_READ 0 |
26 |
|
#define DEBUG_WRITE 0 |
27 |
|
|
28 |
/* Default disk parameters: 4 heads, 32 sectors per track */ |
/* Default disk parameters: 4 heads, 32 sectors per track */ |
29 |
#define DISK_NR_HEADS 4 |
#define DISK_NR_HEADS 4 |
143 |
{ |
{ |
144 |
off_t disk_offset = (off_t)sect * SECTOR_SIZE; |
off_t disk_offset = (off_t)sect * SECTOR_SIZE; |
145 |
|
|
146 |
|
#if DEBUG_READ |
147 |
|
vm_log(d->vm,d->dev.name,"reading sector 0x%8.8x\n",sect); |
148 |
|
#endif |
149 |
|
|
150 |
if (lseek(d->fd,disk_offset,SEEK_SET) == -1) { |
if (lseek(d->fd,disk_offset,SEEK_SET) == -1) { |
151 |
perror("read_sector: lseek"); |
perror("read_sector: lseek"); |
152 |
return(-1); |
return(-1); |
166 |
{ |
{ |
167 |
off_t disk_offset = (off_t)sect * SECTOR_SIZE; |
off_t disk_offset = (off_t)sect * SECTOR_SIZE; |
168 |
|
|
169 |
|
#if DEBUG_WRITE |
170 |
|
vm_log(d->vm,d->dev.name,"writing sector 0x%8.8x\n",sect); |
171 |
|
#endif |
172 |
|
|
173 |
if (lseek(d->fd,disk_offset,SEEK_SET) == -1) { |
if (lseek(d->fd,disk_offset,SEEK_SET) == -1) { |
174 |
perror("write_sector: lseek"); |
perror("write_sector: lseek"); |
175 |
return(-1); |
return(-1); |
192 |
sect_count = d->nr_heads * d->nr_cylinders * d->sects_per_track; |
sect_count = d->nr_heads * d->nr_cylinders * d->sects_per_track; |
193 |
|
|
194 |
/* Clear all fields (for safety) */ |
/* Clear all fields (for safety) */ |
195 |
memset(p,0,SECTOR_SIZE); |
memset(p,0x00,SECTOR_SIZE); |
196 |
|
|
197 |
/* Word 0: General Configuration */ |
/* Word 0: General Configuration */ |
198 |
p[0] = 0x8a; |
p[0] = 0x8a; |
232 |
/* Word 56: Current number of sectors per track */ |
/* Word 56: Current number of sectors per track */ |
233 |
p[112] = d->sects_per_track; |
p[112] = d->sects_per_track; |
234 |
|
|
235 |
/* Word 57/58: Current of sectors per card (MSW/LSW) */ |
/* Word 57/58: Current of sectors per card (LSW/MSW) */ |
236 |
p[114] = (sect_count >> 16) & 0xFF; |
p[114] = sect_count & 0xFF; |
237 |
p[115] = (sect_count >> 24); |
p[115] = (sect_count >> 8) & 0xFF; |
238 |
p[116] = sect_count & 0xFF; |
|
239 |
p[117] = (sect_count >> 8) & 0xFF; |
p[116] = (sect_count >> 16) & 0xFF; |
240 |
|
p[117] = (sect_count >> 24); |
241 |
|
|
242 |
|
#if 0 |
243 |
/* Word 60/61: Total sectors addressable in LBA mode (MSW/LSW) */ |
/* Word 60/61: Total sectors addressable in LBA mode (MSW/LSW) */ |
244 |
p[120] = (sect_count >> 16) & 0xFF; |
p[120] = (sect_count >> 16) & 0xFF; |
245 |
p[121] = (sect_count >> 24); |
p[121] = (sect_count >> 24); |
246 |
p[122] = sect_count & 0xFF; |
p[122] = sect_count & 0xFF; |
247 |
p[123] = (sect_count >> 8) & 0xFF; |
p[123] = (sect_count >> 8) & 0xFF; |
248 |
|
#endif |
249 |
} |
} |
250 |
|
|
251 |
/* Set sector position */ |
/* Set sector position */ |
254 |
u_int cyl; |
u_int cyl; |
255 |
|
|
256 |
if (d->head & ATA_DH_LBA) { |
if (d->head & ATA_DH_LBA) { |
257 |
/* TODO */ |
d->sect_pos = (u_int)(d->head & 0x0F) << 24; |
258 |
} |
d->sect_pos |= (u_int)d->cyl_high << 16; |
259 |
|
d->sect_pos |= (u_int)d->cyl_low << 8; |
260 |
|
d->sect_pos |= (u_int)d->sect_no; |
261 |
|
|
262 |
cyl = (((u_int)d->cyl_high) << 8) + d->cyl_low; |
#if DEBUG_ATA |
263 |
d->sect_pos = chs_to_lba(d,cyl,d->head & 0x0F,d->sect_no); |
vm_log(d->vm,d->dev.name,"ata_set_sect_pos: LBA sect=0x%x\n", |
264 |
|
d->sect_pos); |
265 |
|
#endif |
266 |
|
} else { |
267 |
|
cyl = (((u_int)d->cyl_high) << 8) + d->cyl_low; |
268 |
|
d->sect_pos = chs_to_lba(d,cyl,d->head & 0x0F,d->sect_no); |
269 |
|
|
270 |
|
#if DEBUG_ATA |
271 |
|
vm_log(d->vm,d->dev.name, |
272 |
|
"ata_set_sect_pos: cyl=0x%x,head=0x%x,sect=0x%x => " |
273 |
|
"sect_pos=0x%x\n", |
274 |
|
cyl,d->head & 0x0F,d->sect_no,d->sect_pos); |
275 |
|
#endif |
276 |
|
} |
277 |
} |
} |
278 |
|
|
279 |
/* ATA device identifier callback */ |
/* ATA device identifier callback */ |
320 |
vm_log(d->vm,d->dev.name,"ATA command 0x%2.2x\n",(u_int)d->ata_cmd); |
vm_log(d->vm,d->dev.name,"ATA command 0x%2.2x\n",(u_int)d->ata_cmd); |
321 |
#endif |
#endif |
322 |
|
|
323 |
|
d->data_pos = 0; |
324 |
|
|
325 |
switch(d->ata_cmd) { |
switch(d->ata_cmd) { |
326 |
case ATA_CMD_IDENT_DEVICE: |
case ATA_CMD_IDENT_DEVICE: |
327 |
ata_identify_device(d); |
ata_identify_device(d); |
359 |
} |
} |
360 |
|
|
361 |
/* |
/* |
362 |
* dev_pcmcia_disk_access() |
* dev_pcmcia_disk_access_0() |
363 |
*/ |
*/ |
364 |
void *dev_pcmcia_disk_access(cpu_mips_t *cpu,struct vdevice *dev, |
void *dev_pcmcia_disk_access_0(cpu_mips_t *cpu,struct vdevice *dev, |
365 |
m_uint32_t offset,u_int op_size,u_int op_type, |
m_uint32_t offset,u_int op_size,u_int op_type, |
366 |
m_uint64_t *data) |
m_uint64_t *data) |
367 |
{ |
{ |
368 |
struct pcmcia_disk_data *d = dev->priv_data; |
struct pcmcia_disk_data *d = dev->priv_data; |
|
m_uint32_t d_offset; |
|
369 |
|
|
370 |
/* Compute the good internal offset */ |
/* Compute the good internal offset */ |
371 |
offset = (offset >> 1) ^ 1; |
offset = (offset >> 1) ^ 1; |
419 |
*data = (d->ata_status << 8) + d->head; |
*data = (d->ata_status << 8) + d->head; |
420 |
else { |
else { |
421 |
d->ata_cmd = *data >> 8; |
d->ata_cmd = *data >> 8; |
422 |
d->head = *data & 0xFF; |
d->head = *data; |
423 |
ata_handle_cmd(d); |
ata_handle_cmd(d); |
424 |
} |
} |
425 |
break; |
break; |
429 |
if ((offset >= d->data_offset) && |
if ((offset >= d->data_offset) && |
430 |
(offset < d->data_offset + (SECTOR_SIZE/2))) |
(offset < d->data_offset + (SECTOR_SIZE/2))) |
431 |
{ |
{ |
|
d_offset = offset - d->data_offset; |
|
|
|
|
432 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
433 |
*data = d->data_buffer[(d_offset << 1)]; |
*data = d->data_buffer[(d->data_pos << 1)]; |
434 |
*data += d->data_buffer[(d_offset << 1)+1] << 8; |
*data += d->data_buffer[(d->data_pos << 1)+1] << 8; |
435 |
} else { |
} else { |
436 |
d->data_buffer[(d_offset << 1)] = *data & 0xFF; |
d->data_buffer[(d->data_pos << 1)] = *data & 0xFF; |
437 |
d->data_buffer[(d_offset << 1)+1] = *data >> 8; |
d->data_buffer[(d->data_pos << 1)+1] = *data >> 8; |
438 |
} |
} |
439 |
|
|
440 |
|
d->data_pos++; |
441 |
|
|
442 |
/* Validate data transfer */ |
/* Buffer complete: call the callback function */ |
443 |
if (d_offset == d->data_pos) { |
if (d->data_pos == (SECTOR_SIZE/2)) { |
444 |
d->data_pos++; |
d->data_pos = 0; |
445 |
|
|
446 |
/* Buffer validated: call the callback function */ |
if (d->ata_cmd_callback) |
447 |
if (d->data_pos == (SECTOR_SIZE/2)) { |
d->ata_cmd_callback(d); |
|
d->data_pos = 0; |
|
|
|
|
|
if (d->ata_cmd_callback) |
|
|
d->ata_cmd_callback(d); |
|
|
} |
|
448 |
} |
} |
449 |
} |
} |
450 |
} |
} |
452 |
return NULL; |
return NULL; |
453 |
} |
} |
454 |
|
|
455 |
|
/* |
456 |
|
* dev_pcmcia_disk_access_1() |
457 |
|
*/ |
458 |
|
void *dev_pcmcia_disk_access_1(cpu_mips_t *cpu,struct vdevice *dev, |
459 |
|
m_uint32_t offset,u_int op_size,u_int op_type, |
460 |
|
m_uint64_t *data) |
461 |
|
{ |
462 |
|
struct pcmcia_disk_data *d = dev->priv_data; |
463 |
|
|
464 |
|
/* Compute the good internal offset */ |
465 |
|
offset = (offset >> 1) ^ 1; |
466 |
|
|
467 |
|
#if DEBUG_ACCESS |
468 |
|
if (op_type == MTS_READ) { |
469 |
|
cpu_log(cpu,d->dev.name, |
470 |
|
"reading offset 0x%5.5x at pc=0x%llx (size=%u)\n", |
471 |
|
offset,cpu->pc,op_size); |
472 |
|
} else { |
473 |
|
cpu_log(cpu,d->dev.name, |
474 |
|
"writing offset 0x%5.5x, data=0x%llx at pc=0x%llx (size=%u)\n", |
475 |
|
offset,*data,cpu->pc,op_size); |
476 |
|
} |
477 |
|
#endif |
478 |
|
|
479 |
|
switch(offset) { |
480 |
|
case 0x02: /* Sector Count + Sector no */ |
481 |
|
if (op_type == MTS_READ) { |
482 |
|
*data = (d->sect_no << 8) + d->sect_count; |
483 |
|
} else { |
484 |
|
d->sect_no = *data >> 8; |
485 |
|
d->sect_count = *data & 0xFF; |
486 |
|
} |
487 |
|
break; |
488 |
|
|
489 |
|
case 0x04: /* Cylinder Low + Cylinder High */ |
490 |
|
if (op_type == MTS_READ) { |
491 |
|
*data = (d->cyl_high << 8) + d->cyl_low; |
492 |
|
} else { |
493 |
|
d->cyl_high = *data >> 8; |
494 |
|
d->cyl_low = *data & 0xFF; |
495 |
|
} |
496 |
|
break; |
497 |
|
|
498 |
|
case 0x06: /* Select Card/Head + Status/Command register */ |
499 |
|
if (op_type == MTS_READ) |
500 |
|
*data = (d->ata_status << 8) + d->head; |
501 |
|
else { |
502 |
|
d->ata_cmd = *data >> 8; |
503 |
|
d->head = *data & 0xFF; |
504 |
|
ata_handle_cmd(d); |
505 |
|
} |
506 |
|
break; |
507 |
|
|
508 |
|
case 0x08: |
509 |
|
if (op_type == MTS_READ) { |
510 |
|
*data = d->data_buffer[(d->data_pos << 1)]; |
511 |
|
*data += d->data_buffer[(d->data_pos << 1)+1] << 8; |
512 |
|
} else { |
513 |
|
d->data_buffer[(d->data_pos << 1)] = *data & 0xFF; |
514 |
|
d->data_buffer[(d->data_pos << 1)+1] = *data >> 8; |
515 |
|
} |
516 |
|
|
517 |
|
d->data_pos++; |
518 |
|
|
519 |
|
/* Buffer complete: call the callback function */ |
520 |
|
if (d->data_pos == (SECTOR_SIZE/2)) { |
521 |
|
d->data_pos = 0; |
522 |
|
|
523 |
|
if (d->ata_cmd_callback) |
524 |
|
d->ata_cmd_callback(d); |
525 |
|
} |
526 |
|
break; |
527 |
|
|
528 |
|
case 0x0E: |
529 |
|
break; |
530 |
|
} |
531 |
|
|
532 |
|
return NULL; |
533 |
|
} |
534 |
|
|
535 |
/* Shutdown a PCMCIA disk device */ |
/* Shutdown a PCMCIA disk device */ |
536 |
void dev_pcmcia_disk_shutdown(vm_instance_t *vm,struct pcmcia_disk_data *d) |
void dev_pcmcia_disk_shutdown(vm_instance_t *vm,struct pcmcia_disk_data *d) |
537 |
{ |
{ |
553 |
/* Initialize a PCMCIA disk */ |
/* Initialize a PCMCIA disk */ |
554 |
vm_obj_t *dev_pcmcia_disk_init(vm_instance_t *vm,char *name, |
vm_obj_t *dev_pcmcia_disk_init(vm_instance_t *vm,char *name, |
555 |
m_uint64_t paddr,m_uint32_t len, |
m_uint64_t paddr,m_uint32_t len, |
556 |
u_int disk_size) |
u_int disk_size,int mode) |
557 |
{ |
{ |
558 |
struct pcmcia_disk_data *d; |
struct pcmcia_disk_data *d; |
559 |
m_uint32_t tot_sect; |
m_uint32_t tot_sect; |
601 |
d->dev.phys_addr = paddr; |
d->dev.phys_addr = paddr; |
602 |
d->dev.phys_len = len; |
d->dev.phys_len = len; |
603 |
d->dev.flags = VDEVICE_FLAG_CACHING; |
d->dev.flags = VDEVICE_FLAG_CACHING; |
604 |
d->dev.handler = dev_pcmcia_disk_access; |
|
605 |
|
if (mode == 0) |
606 |
|
d->dev.handler = dev_pcmcia_disk_access_0; |
607 |
|
else |
608 |
|
d->dev.handler = dev_pcmcia_disk_access_1; |
609 |
|
|
610 |
/* Map this device to the VM */ |
/* Map this device to the VM */ |
611 |
vm_bind_device(vm,&d->dev); |
vm_bind_device(vm,&d->dev); |