38 static const byte MT_UNKNOWN = 0x00;
39 static const byte MT_2DD_UN = 0x10;
40 static const byte MT_2DD = 0x11;
41 static const byte MT_2HD_UN = 0x20;
42 static const byte MT_2HD_12_98 = 0x22;
43 static const byte MT_2HD_12 = 0x23;
44 static const byte MT_2HD_144 = 0x24;
45 static const byte MT_LS120 = 0x31;
46 static const byte MT_NO_DISK = 0x70;
47 static const byte MT_DOOR_OPEN = 0x71;
48 static const byte MT_FMT_ERROR = 0x72;
50 static const byte inqdata[36] = {
61 'o',
'p',
'e',
'n',
'M',
'S',
'X',
' ',
62 'S',
'C',
'S',
'I',
'2',
' ',
'H',
'a',
63 'r',
'd',
'd',
'i',
's',
'k',
' ',
' ',
71 byte*
const buf,
unsigned mode_)
73 , motherBoard(targetconfig.getMotherBoard())
76 , scsiId(targetconfig.getAttributeAsInt(
"id"))
83 PRT_DEBUG(
"hdd close for hdd " <<
int(scsiId));
93 void SCSIHD::busReset()
95 PRT_DEBUG(
"SCSI: bus reset on " <<
int(scsiId));
100 void SCSIHD::disconnect()
106 bool SCSIHD::isSelected()
112 unsigned SCSIHD::inquiry()
114 unsigned length = currentLength;
116 if (length == 0)
return 0;
118 memcpy(buffer + 2, inqdata + 2, 34);
120 buffer[0] = SCSI::DT_DirectAccess;
135 length = std::min(length, 96u);
138 memset(buffer + 56, 0, 40);
144 length = std::min(length, 56u);
150 filename.resize(20,
' ');
151 memcpy(buffer + 36, filename.data(), 20);
156 unsigned SCSIHD::modeSense()
158 byte* pBuffer = buffer;
159 if ((currentLength > 0) && (cdb[2] == 3)) {
162 byte media = MT_UNKNOWN;
167 byte removable = 0x80;
169 memset(pBuffer + 2, 0, 34);
181 if (!(cdb[1] & 0x08)) {
183 pBuffer[1] = (total >> 16) & 0xff;
184 pBuffer[2] = (total >> 8) & 0xff;
185 pBuffer[3] = (total >> 0) & 0xff;
186 pBuffer[6] = blockLength & 0xff;
194 pBuffer[ 3] = tracks;
195 pBuffer[11] = sectors;
196 pBuffer[12] = blockLength;
197 pBuffer[20] = removable;
199 buffer[0] = size - 1;
201 return std::min<unsigned>(currentLength,
size);
203 keycode = SCSI::SENSE_INVALID_COMMAND_CODE;
207 unsigned SCSIHD::requestSense()
209 unsigned length = currentLength;
210 unsigned tmpKeycode = unitAttention ? SCSI::SENSE_POWER_ON : keycode;
211 unitAttention =
false;
213 PRT_DEBUG(
"Request Sense: keycode = " << tmpKeycode);
214 keycode = SCSI::SENSE_NO_SENSE;
216 memset(buffer + 1, 0, 17);
218 if (mode & BIT_SCSI2) {
221 buffer[ 0] = (tmpKeycode >> 8) & 0xff;
225 buffer[ 2] = (tmpKeycode >> 16) & 0xff;
227 buffer[12] = (tmpKeycode >> 8) & 0xff;
228 buffer[13] = (tmpKeycode >> 0) & 0xff;
229 length = std::min(length, 18u);
234 bool SCSIHD::checkReadOnly()
237 keycode = SCSI::SENSE_WRITE_PROTECT;
243 unsigned SCSIHD::readCapacity()
249 keycode = SCSI::SENSE_MEDIUM_NOT_PRESENT;
250 PRT_DEBUG(
"hdd " <<
int(scsiId) <<
": drive not ready");
257 Endian::write_UA_B32(&buffer[0], block);
262 bool SCSIHD::checkAddress()
266 keycode = SCSI::SENSE_MEDIUM_NOT_PRESENT;
267 PRT_DEBUG(
"hdd " <<
int(scsiId) <<
": drive not ready");
271 if ((currentLength > 0) && (currentSector + currentLength <= total)) {
274 PRT_DEBUG(
"hdd " <<
int(scsiId) <<
": IllegalBlockAddress");
275 keycode = SCSI::SENSE_ILLEGAL_BLOCK_ADDRESS;
280 unsigned SCSIHD::readSectors(
unsigned& blocks)
284 unsigned numSectors = std::min(currentLength, BUFFER_BLOCK_SIZE);
287 PRT_DEBUG(
"hdd#" <<
int(scsiId) <<
" read sector: " << currentSector <<
' ' << numSectors);
289 for (
unsigned i = 0; i < numSectors; ++i) {
290 readSector(currentSector, &buffer[i * SECTOR_SIZE]);
294 blocks = currentLength;
296 }
catch (MSXException&) {
298 keycode = SCSI::SENSE_UNRECOVERED_READ_ERROR;
303 unsigned SCSIHD::dataIn(
unsigned& blocks)
305 if (cdb[0] == SCSI::OP_READ10) {
306 unsigned counter = readSectors(blocks);
317 unsigned SCSIHD::writeSectors(
unsigned& blocks)
321 unsigned numSectors = std::min(currentLength, BUFFER_BLOCK_SIZE);
323 PRT_DEBUG(
"hdd#" <<
int(scsiId) <<
" write sector: " << currentSector <<
' ' << numSectors);
325 for (
unsigned i = 0; i < numSectors; ++i) {
326 writeSector(currentSector, &buffer[i * SECTOR_SIZE]);
331 unsigned tmp = std::min(currentLength, BUFFER_BLOCK_SIZE);
332 blocks = currentLength - tmp;
335 }
catch (MSXException&) {
336 keycode = SCSI::SENSE_WRITE_FAULT;
342 unsigned SCSIHD::dataOut(
unsigned& blocks)
344 if (cdb[0] == SCSI::OP_WRITE10) {
345 return writeSectors(blocks);
347 PRT_DEBUG(
"dataOut error " <<
int(cdb[0]));
353 void SCSIHD::formatUnit()
355 if (!checkReadOnly()) {
356 memset(buffer, 0, SECTOR_SIZE);
359 unitAttention =
true;
360 }
catch (MSXException&) {
361 keycode = SCSI::SENSE_WRITE_FAULT;
366 byte SCSIHD::getStatusCode()
368 byte result = keycode ? SCSI::ST_CHECK_CONDITION : SCSI::ST_GOOD;
369 PRT_DEBUG(
"SCSI status code: \n" <<
int(result));
373 unsigned SCSIHD::executeCmd(
const byte* cdb_,
SCSI::Phase& phase,
unsigned& blocks)
375 PRT_DEBUG(
"SCSI Command: " <<
int(cdb[0]));
376 memcpy(cdb, cdb_,
sizeof(cdb));
383 (cdb[0] != SCSI::OP_INQUIRY) && (cdb[0] != SCSI::OP_REQUEST_SENSE)) {
384 unitAttention =
false;
385 keycode = SCSI::SENSE_POWER_ON;
386 if (cdb[0] == SCSI::OP_TEST_UNIT_READY) {
389 PRT_DEBUG(
"Unit Attention. This command is not executed.");
394 if (((cdb[1] & 0xe0) || lun) && (cdb[0] != SCSI::OP_REQUEST_SENSE) &&
395 !(cdb[0] == SCSI::OP_INQUIRY && !(mode &
MODE_NOVAXIS))) {
396 keycode = SCSI::SENSE_INVALID_LUN;
401 if (cdb[0] != SCSI::OP_REQUEST_SENSE) {
402 keycode = SCSI::SENSE_NO_SENSE;
405 if (cdb[0] < SCSI::OP_GROUP1) {
406 currentSector = ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
407 currentLength = cdb[4];
410 case SCSI::OP_TEST_UNIT_READY:
414 case SCSI::OP_INQUIRY: {
416 unsigned counter = inquiry();
422 case SCSI::OP_REQUEST_SENSE: {
424 unsigned counter = requestSense();
431 PRT_DEBUG(
"Read6: " << currentSector <<
' ' << currentLength);
432 if (currentLength == 0) {
433 currentLength = SECTOR_SIZE / 2;
435 if (checkAddress()) {
436 unsigned counter = readSectors(blocks);
438 cdb[0] = SCSI::OP_READ10;
445 case SCSI::OP_WRITE6:
446 PRT_DEBUG(
"Write6: " << currentSector <<
' ' << currentLength);
447 if (currentLength == 0) {
448 currentLength = SECTOR_SIZE / 2;
450 if (checkAddress() && !checkReadOnly()) {
452 unsigned tmp = std::min(currentLength, BUFFER_BLOCK_SIZE);
453 blocks = currentLength - tmp;
455 cdb[0] = SCSI::OP_WRITE10;
468 case SCSI::OP_MODE_SENSE: {
469 PRT_DEBUG(
"ModeSense: " << currentLength);
470 unsigned counter = modeSense();
476 case SCSI::OP_FORMAT_UNIT:
481 case SCSI::OP_START_STOP_UNIT:
482 PRT_DEBUG(
"StartStopUnit (Not supported for this device.)");
485 case SCSI::OP_REZERO_UNIT:
486 case SCSI::OP_REASSIGN_BLOCKS:
487 case SCSI::OP_RESERVE_UNIT:
488 case SCSI::OP_RELEASE_UNIT:
489 case SCSI::OP_SEND_DIAGNOSTIC:
494 currentSector = Endian::read_UA_B32(&cdb[2]);
495 currentLength = Endian::read_UA_B16(&cdb[7]);
498 case SCSI::OP_READ10:
499 PRT_DEBUG(
"Read10: " << currentSector <<
' ' << currentLength);
501 if (checkAddress()) {
502 unsigned counter = readSectors(blocks);
510 case SCSI::OP_WRITE10:
511 PRT_DEBUG(
"Write10: " << currentSector <<
' ' << currentLength);
513 if (checkAddress() && !checkReadOnly()) {
514 unsigned tmp = std::min(currentLength, BUFFER_BLOCK_SIZE);
515 blocks = currentLength - tmp;
522 case SCSI::OP_READ_CAPACITY: {
524 unsigned counter = readCapacity();
530 case SCSI::OP_SEEK10:
539 PRT_DEBUG(
"unsupported command " << cdb[0]);
540 keycode = SCSI::SENSE_INVALID_COMMAND_CODE;
544 unsigned SCSIHD::executingCmd(
SCSI::Phase& phase,
unsigned& blocks)
553 byte result = message;
568 int SCSIHD::msgOut(
byte value)
570 PRT_DEBUG(
"SCSI #" <<
int(scsiId) <<
" message out: " <<
int(value));
577 case SCSI::MSG_INITIATOR_DETECT_ERROR:
578 keycode = SCSI::SENSE_INITIATOR_DETECTED_ERR;
581 case SCSI::MSG_BUS_DEVICE_RESET:
584 case SCSI::MSG_ABORT:
587 case SCSI::MSG_REJECT:
588 case SCSI::MSG_PARITY_ERROR:
589 case SCSI::MSG_NO_OPERATION:
592 message = SCSI::MSG_REJECT;
593 return ((value >= 0x04) && (value <= 0x11)) ? 3 : 1;
597 template<
typename Archive>
602 ar.template serializeBase<HD>(*this);
603 ar.serialize(
"keycode", keycode);
604 ar.serialize(
"currentSector", currentSector);
605 ar.serialize(
"currentLength", currentLength);
606 ar.serialize(
"unitAttention", unitAttention);
607 ar.serialize(
"message", message);
608 ar.serialize(
"lun", lun);
609 ar.serialize_blob(
"cdb", cdb,
sizeof(cdb));