// license:BSD-3-Clause // copyright-holders:smf #include "emu.h" #include "t10sbc.h" void t10sbc::t10_start(device_t &device) { m_device = &device; t10spc::t10_start(device); device.save_item( NAME( m_lba ) ); device.save_item( NAME( m_blocks ) ); } void t10sbc::t10_reset() { t10spc::t10_reset(); m_lba = 0; m_blocks = 0; m_sector_bytes = 512; m_disk = m_image->get_hard_disk_file(); if (!m_disk) { m_device->logerror("T10SBC %s: no HD found!\n", m_image->owner()->tag()); } else { // get hard disk sector size from CHD metadata const hard_disk_info *hdinfo = hard_disk_get_info(m_disk); m_sector_bytes = hdinfo->sectorbytes; } } // scsihd_exec_command void t10sbc::ExecCommand() { switch ( command[0] ) { case T10SBC_CMD_FORMAT_UNIT: m_phase = SCSI_PHASE_STATUS; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = 0; break; case T10SBC_CMD_SEEK_6: m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; m_device->logerror("S1410: SEEK to LBA %x\n", m_lba); m_phase = SCSI_PHASE_STATUS; m_transfer_length = 0; break; case T10SBC_CMD_READ_6: m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; m_blocks = SCSILengthFromUINT8( &command[4] ); m_device->logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks); m_phase = SCSI_PHASE_DATAIN; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = m_blocks * m_sector_bytes; break; case T10SBC_CMD_WRITE_6: m_lba = (command[1]&0x1f)<<16 | command[2]<<8 | command[3]; m_blocks = SCSILengthFromUINT8( &command[4] ); m_device->logerror("T10SBC: WRITE to LBA %x for %x blocks\n", m_lba, m_blocks); m_phase = SCSI_PHASE_DATAOUT; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = m_blocks * m_sector_bytes; break; case T10SPC_CMD_INQUIRY: m_phase = SCSI_PHASE_DATAIN; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); break; case T10SPC_CMD_MODE_SELECT_6: m_device->logerror("T10SBC: MODE SELECT length %x control %x\n", command[4], command[5]); m_phase = SCSI_PHASE_DATAOUT; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); break; case T10SPC_CMD_MODE_SENSE_6: m_phase = SCSI_PHASE_DATAIN; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = SCSILengthFromUINT8( &command[ 4 ] ); break; case T10SBC_CMD_READ_CAPACITY: m_phase = SCSI_PHASE_DATAIN; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = 8; break; case T10SBC_CMD_READ_10: m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; m_blocks = SCSILengthFromUINT16( &command[7] ); m_device->logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks); m_phase = SCSI_PHASE_DATAIN; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = m_blocks * m_sector_bytes; break; case T10SBC_CMD_WRITE_10: m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; m_blocks = SCSILengthFromUINT16( &command[7] ); m_device->logerror("T10SBC: WRITE to LBA %x for %x blocks\n", m_lba, m_blocks); m_phase = SCSI_PHASE_DATAOUT; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = m_blocks * m_sector_bytes; break; case T10SBC_CMD_READ_12: m_lba = command[2]<<24 | command[3]<<16 | command[4]<<8 | command[5]; m_blocks = command[6]<<24 | command[7]<<16 | command[8]<<8 | command[9]; m_device->logerror("T10SBC: READ at LBA %x for %x blocks\n", m_lba, m_blocks); m_phase = SCSI_PHASE_DATAIN; m_status_code = SCSI_STATUS_CODE_GOOD; m_transfer_length = m_blocks * m_sector_bytes; break; default: t10spc::ExecCommand(); break; } } void t10sbc::ReadData( uint8_t *data, int dataLength ) { // if we're a drive without a disk, return all zeroes if (!m_disk) { memset(data, 0, dataLength); return; } switch ( command[0] ) { case T10SPC_CMD_INQUIRY: memset( data, 0, dataLength ); data[0] = 0x00; // device is direct-access (e.g. hard disk) data[1] = 0x00; // media is not removable data[2] = 0x05; // device complies with SPC-3 standard data[3] = 0x02; // response data format = SPC-3 standard // Apple HD SC setup utility needs to see this strcpy((char *)&data[8], " SEAGATE"); strcpy((char *)&data[16], " ST225N"); strcpy((char *)&data[32], "1.0"); break; case T10SPC_CMD_MODE_SENSE_6: // special Apple ID page. this is a vendor-specific page, // so unless collisions occur there should be no need // to change it. if ((command[2] & 0x3f) == 0x30) { memset(data, 0, 40); data[0] = 0x14; strcpy((char *)&data[14], "APPLE COMPUTER, INC."); } break; case T10SBC_CMD_READ_6: case T10SBC_CMD_READ_10: case T10SBC_CMD_READ_12: if ((m_disk) && (m_blocks)) { while (dataLength > 0) { if (!hard_disk_read(m_disk, m_lba, data)) { m_device->logerror("T10SBC: HD read error!\n"); } m_lba++; m_blocks--; dataLength -= m_sector_bytes; data += m_sector_bytes; } } break; case T10SBC_CMD_READ_CAPACITY: // READ CAPACITY { hard_disk_info *info; uint32_t temp; info = hard_disk_get_info(m_disk); m_device->logerror("T10SBC: READ CAPACITY\n"); // get # of sectors temp = info->cylinders * info->heads * info->sectors; temp--; data[0] = (temp>>24) & 0xff; data[1] = (temp>>16) & 0xff; data[2] = (temp>>8) & 0xff; data[3] = (temp & 0xff); data[4] = (info->sectorbytes>>24)&0xff; data[5] = (info->sectorbytes>>16)&0xff; data[6] = (info->sectorbytes>>8)&0xff; data[7] = (info->sectorbytes & 0xff); } break; default: t10spc::ReadData( data, dataLength ); break; } } void t10sbc::WriteData( uint8_t *data, int dataLength ) { if (!m_disk) { return; } switch ( command[0] ) { case T10SPC_CMD_MODE_SELECT_6: break; case T10SBC_CMD_WRITE_6: case T10SBC_CMD_WRITE_10: if ((m_disk) && (m_blocks)) { while (dataLength > 0) { if (!hard_disk_write(m_disk, m_lba, data)) { m_device->logerror("T10SBC: HD write error!\n"); } m_lba++; m_blocks--; dataLength -= m_sector_bytes; data += m_sector_bytes; } } break; default: t10spc::WriteData( data, dataLength ); break; } } void t10sbc::GetDevice( void **_disk ) { *(hard_disk_file **)_disk = m_disk; } void t10sbc::SetDevice( void *_disk ) { m_disk = (hard_disk_file *)_disk; }