diff --git a/devices/common/scsi/scsicdrom.cpp b/devices/common/scsi/scsicdrom.cpp
index b15ff47..515f192 100644
--- a/devices/common/scsi/scsicdrom.cpp
+++ b/devices/common/scsi/scsicdrom.cpp
@@ -24,8 +24,9 @@ along with this program. If not, see .
#include
#include
#include
-#include
#include
+#include
+#include
#include
#include
@@ -103,9 +104,15 @@ void ScsiCdrom::process_command()
this->eject_allowed = (this->cmd_buf[4] & 1) == 0;
this->switch_phase(ScsiPhase::STATUS);
break;
+ case ScsiCommand::READ_CAPACITY_10:
+ this->read_capacity();
+ break;
case ScsiCommand::READ_10:
- lba = (cmd_buf[2] << 24) + (cmd_buf[3] << 16) + (cmd_buf[4] << 8) + cmd_buf[5];
- xfer_len = (cmd_buf[7] << 8) + cmd_buf[8];
+ lba = READ_DWORD_BE_U(&this->cmd_buf[2]);
+ xfer_len = READ_WORD_BE_U(&this->cmd_buf[7]);
+ if (this->cmd_buf[1] & 1) {
+ ABORT_F("SCSI-CDROM: RelAdr bit set in READ_10");
+ }
read(lba, xfer_len, 10);
break;
case ScsiCommand::READ_TOC:
@@ -264,6 +271,8 @@ void ScsiCdrom::read_toc()
LOG_F(ERROR, "SCSI-CDROM: invalid starting track %d in READ_TOC", start_track);
this->status = ScsiStatus::CHECK_CONDITION;
this->sense = ScsiSense::ILLEGAL_REQ;
+ this->switch_phase(ScsiPhase::STATUS);
+ return;
}
char* buf_ptr = this->data_buf;
@@ -301,7 +310,40 @@ void ScsiCdrom::read_toc()
}
}
- this->bytes_out = alloc_len;
+ this->bytes_out = alloc_len;
+ this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE;
+
+ this->switch_phase(ScsiPhase::DATA_IN);
+}
+
+void ScsiCdrom::read_capacity()
+{
+ uint32_t lba = READ_DWORD_BE_U(&this->cmd_buf[2]);
+
+ if (this->cmd_buf[1] & 1) {
+ ABORT_F("SCSI-CDROM: RelAdr bit set in READ_CAPACITY_10");
+ }
+
+ if (!(this->cmd_buf[8] & 1) && lba) {
+ LOG_F(ERROR, "SCSI-CDROM: non-zero LBA for PMI=0");
+ this->status = ScsiStatus::CHECK_CONDITION;
+ this->sense = ScsiSense::ILLEGAL_REQ;
+ this->switch_phase(ScsiPhase::STATUS);
+ return;
+ }
+
+ int last_lba = this->total_frames - 1;
+
+ this->data_buf[0] = (last_lba >> 24) & 0xFFU;
+ this->data_buf[1] = (last_lba >> 16) & 0xFFU;
+ this->data_buf[2] = (last_lba >> 8) & 0xFFU;
+ this->data_buf[3] = (last_lba >> 0) & 0xFFU;
+ this->data_buf[4] = 0;
+ this->data_buf[5] = 0;
+ this->data_buf[6] = (this->sector_size >> 8) & 0xFFU;
+ this->data_buf[7] = this->sector_size & 0xFFU;
+
+ this->bytes_out = 8;
this->msg_buf[0] = ScsiMessage::COMMAND_COMPLETE;
this->switch_phase(ScsiPhase::DATA_IN);
diff --git a/devices/common/scsi/scsicdrom.h b/devices/common/scsi/scsicdrom.h
index 72d7000..a4a8674 100644
--- a/devices/common/scsi/scsicdrom.h
+++ b/devices/common/scsi/scsicdrom.h
@@ -68,6 +68,7 @@ protected:
void inquiry();
void mode_sense();
void read_toc();
+ void read_capacity();
private:
AddrMsf lba_to_msf(const int lba);