diff --git a/devices/common/scsi/scsi.h b/devices/common/scsi/scsi.h index 11f6bd0..6952323 100644 --- a/devices/common/scsi/scsi.h +++ b/devices/common/scsi/scsi.h @@ -200,6 +200,8 @@ public: this->bus_obj = bus_obj_ptr; } + void report_error(uint8_t sense_key, uint8_t asc); + protected: uint8_t cmd_buf[16] = {}; uint8_t msg_buf[16] = {}; // TODO: clarify how big this one should be diff --git a/devices/common/scsi/scsicdrom.cpp b/devices/common/scsi/scsicdrom.cpp index 7ca31ce..46cf684 100644 --- a/devices/common/scsi/scsicdrom.cpp +++ b/devices/common/scsi/scsicdrom.cpp @@ -34,6 +34,11 @@ using namespace std; ScsiCdrom::ScsiCdrom(std::string name, int my_id) : CdromDrive(), ScsiDevice(name, my_id) { + this->set_error_callback( + [this](uint8_t sense_key, uint8_t asc) { + this->report_error(sense_key, asc); + } + ); } void ScsiCdrom::process_command() @@ -85,7 +90,11 @@ void ScsiCdrom::process_command() // CD-ROM specific commands case ScsiCommand::READ_TOC: - this->read_toc(); + this->bytes_out = read_toc(cmd, this->data_buf); + if (this->status == ScsiStatus::GOOD) { + this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE; + this->switch_phase(ScsiPhase::DATA_IN); + } break; default: LOG_F(ERROR, "%s: unsupported command 0x%X", this->name.c_str(), cmd[0]); @@ -270,85 +279,6 @@ void ScsiCdrom::mode_select_6(uint8_t param_len) this->switch_phase(ScsiPhase::DATA_OUT); } -void ScsiCdrom::read_toc() -{ - int tot_tracks; - uint8_t start_track = this->cmd_buf[6]; - uint16_t alloc_len = (this->cmd_buf[7] << 8) + this->cmd_buf[8]; - bool is_msf = !!(this->cmd_buf[1] & 2); - - if (this->cmd_buf[2] & 0xF) { - ABORT_F("%s: unsupported format in READ_TOC", this->name.c_str()); - } - - if (!alloc_len) { - LOG_F(WARNING, "%s: zero allocation length passed to READ_TOC", this->name.c_str()); - return; - } - - if (!start_track) { // special case: track zero (lead-in) as starting track - // return all tracks starting with track 1 plus lead-out - start_track = 1; - tot_tracks = this->num_tracks + 1; - } else if (start_track == LEAD_OUT_TRK_NUM) { - start_track = this->num_tracks + 1; - tot_tracks = 1; - } else if (start_track <= this->num_tracks) { - tot_tracks = (this->num_tracks - start_track) + 2; - } else { - LOG_F(ERROR, "%s: invalid starting track %d in READ_TOC", this->name.c_str(), - start_track); - this->status = ScsiStatus::CHECK_CONDITION; - this->sense = ScsiSense::ILLEGAL_REQ; - this->asc = ScsiError::INVALID_CDB; - this->ascq = 0; - this->sksv = 0xc0; // sksv=1, C/D=Command, BPV=0, BP=0 - this->field = 6; // offset of start_track - this->switch_phase(ScsiPhase::STATUS); - return; - } - - uint8_t* buf_ptr = this->data_buf; - - int data_len = (tot_tracks * 8) + 2; - - // write TOC data header - *buf_ptr++ = (data_len >> 8) & 0xFFU; - *buf_ptr++ = (data_len >> 0) & 0xFFU; - *buf_ptr++ = 1; // 1st track number - *buf_ptr++ = this->num_tracks; // last track number - - for (int tx = 0; tx < tot_tracks; tx++) { - if ((buf_ptr - this->data_buf + 8) > alloc_len) - break; // exit the loop if the output buffer length is exhausted - - TrackDescriptor& td = this->tracks[start_track + tx - 1]; - - *buf_ptr++ = 0; // reserved - *buf_ptr++ = td.adr_ctrl; - *buf_ptr++ = td.trk_num; - *buf_ptr++ = 0; // reserved - - if (is_msf) { - AddrMsf msf = lba_to_msf(td.start_lba + 150); - *buf_ptr++ = 0; // reserved - *buf_ptr++ = msf.min; - *buf_ptr++ = msf.sec; - *buf_ptr++ = msf.frm; - } else { - *buf_ptr++ = (td.start_lba >> 24) & 0xFFU; - *buf_ptr++ = (td.start_lba >> 16) & 0xFFU; - *buf_ptr++ = (td.start_lba >> 8) & 0xFFU; - *buf_ptr++ = (td.start_lba >> 0) & 0xFFU; - } - } - - this->bytes_out = alloc_len; - this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE; - - this->switch_phase(ScsiPhase::DATA_IN); -} - void ScsiCdrom::read_capacity_10() { uint32_t lba = READ_DWORD_BE_U(&this->cmd_buf[2]); diff --git a/devices/common/scsi/scsicdrom.h b/devices/common/scsi/scsicdrom.h index 7dc84f0..6577466 100644 --- a/devices/common/scsi/scsicdrom.h +++ b/devices/common/scsi/scsicdrom.h @@ -48,7 +48,6 @@ protected: void mode_select_6(uint8_t param_len); void mode_sense_6(); - void read_toc(); void read_capacity_10(); private: diff --git a/devices/common/scsi/scsidevice.cpp b/devices/common/scsi/scsidevice.cpp index 9dc113c..d46697e 100644 --- a/devices/common/scsi/scsidevice.cpp +++ b/devices/common/scsi/scsidevice.cpp @@ -246,3 +246,12 @@ void ScsiDevice::illegal_command(const uint8_t *cmd) { this->field = 0; this->switch_phase(ScsiPhase::STATUS); } + +void ScsiDevice::report_error(uint8_t sense_key, uint8_t asc) { + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = sense_key; + this->asc = asc; + this->ascq = 0; + this->sksv = 0xC0; // sksv=1, C/D=Command, BPV=0, BP=0 + this->switch_phase(ScsiPhase::STATUS); +} diff --git a/devices/storage/cdromdrive.cpp b/devices/storage/cdromdrive.cpp index 52424c9..6666467 100644 --- a/devices/storage/cdromdrive.cpp +++ b/devices/storage/cdromdrive.cpp @@ -216,7 +216,7 @@ uint32_t CdromDrive::read_toc(uint8_t *cmd_ptr, uint8_t *data_ptr) { out_ptr += 4; } } - return data_len; + return alloc_len; case 1: // Multi-session info std::memset(data_ptr, 0, 12); data_ptr[1] = 10; // TOC data length