From 44564065f6ad637d1226d7a6a8da29c874d650bf Mon Sep 17 00:00:00 2001 From: joevt Date: Sun, 10 Mar 2024 04:42:40 -0700 Subject: [PATCH] scsihd: Changes for MODE_SENSE_6. Return CHECK_CONDITION for unsupported page_ctrl or page or subpage. Handle the all pages code 0x3F. --- devices/common/scsi/scsihd.cpp | 138 +++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 31 deletions(-) diff --git a/devices/common/scsi/scsihd.cpp b/devices/common/scsi/scsihd.cpp index 90226a4..b02565d 100644 --- a/devices/common/scsi/scsihd.cpp +++ b/devices/common/scsi/scsihd.cpp @@ -266,48 +266,124 @@ static char Apple_Copyright_Page_Data[] = "APPLE COMPUTER, INC "; void ScsiHardDisk::mode_sense_6() { uint8_t page_code = this->cmd_buf[2] & 0x3F; uint8_t page_ctrl = this->cmd_buf[2] >> 6; + uint8_t sub_page_code = this->cmd_buf[3]; uint8_t alloc_len = this->cmd_buf[4]; - this->data_buf[ 0] = 13; // initial data size - this->data_buf[ 1] = 0; // medium type - this->data_buf[ 2] = 0; // medium is write enabled - this->data_buf[ 3] = 8; // block description length + if (page_ctrl == 1) { + LOG_F(INFO, "%s: page_ctrl 1 CHANGEABLE VALUES is not implemented", this->name.c_str()); + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = ScsiSense::ILLEGAL_REQ; + this->asc = 0x24; // Invalid Field in CDB + this->ascq = 0; + this->sksv = 0xc0; // sksv=1, C/D=Command, BPV=0, BP=0 + this->field = 2; + this->switch_phase(ScsiPhase::STATUS); + return; + } + if (page_ctrl == 2) { + LOG_F(ERROR, "%s: page_ctrl 2 DEFAULT VALUES is not implemented", this->name.c_str()); + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = ScsiSense::ILLEGAL_REQ; + this->asc = 0x24; // Invalid Field in CDB + this->ascq = 0; + this->sksv = 0xc0; // sksv=1, C/D=Command, BPV=0, BP=0 + this->field = 2; + this->switch_phase(ScsiPhase::STATUS); + return; + } + + if (page_ctrl == 3) { + LOG_F(INFO, "%s: page_ctrl 3 SAVED VALUES is not implemented", this->name.c_str()); + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = ScsiSense::ILLEGAL_REQ; + this->asc = 0x39; // Saving Parameters Not Supported + this->ascq = 0; + this->sksv = 0; + this->field = 0; + this->switch_phase(ScsiPhase::STATUS); + return; + } + + this->data_buf[ 1] = 0; // medium type + this->data_buf[ 2] = 0; // 0:medium is not write protected; 0x80 write protected + + this->data_buf[ 3] = 8; // block description length WRITE_DWORD_BE_A(&this->data_buf[4], this->total_blocks); WRITE_DWORD_BE_A(&this->data_buf[8], this->sector_size); - this->data_buf[12] = page_code; + uint8_t *p_buf = &this->data_buf[12]; + bool got_page = false; + int page_size; - switch(page_code) { - case 1: // read-write error recovery page - this->data_buf[13] = 6; // data size - 1 - std::memset(&this->data_buf[14], 0, 6); - break; - case 3: // Format device page - this->data_buf[13] = 22; // data size - 1 - std::memset(&this->data_buf[14], 0, 22); + if (page_code == 1 || page_code == 0x3f) { // read-write error recovery page + if (sub_page_code != 0x00 && sub_page_code != 0xff) + goto bad_sub_page; + page_size = 8; + p_buf[0] = 1; // page code + p_buf[1] = page_size - 2; // data size - 1 + std::memset(&p_buf[2], 0, 6); + p_buf += page_size; + got_page = true; + } + + if (page_code == 3 || page_code == 0x3f) { // Format device page + if (sub_page_code != 0x00 && sub_page_code != 0xff) + goto bad_sub_page; + page_size = 24; + p_buf[ 0] = 3; // page code + p_buf[ 1] = page_size - 2; // data size - 1 + std::memset(&p_buf[2], 0, 22); // default values taken from Empire 540/1080S manual - this->data_buf[15] = 6; // tracks per defect zone - this->data_buf[17] = 1; // alternate sectors per zone - this->data_buf[23] = 92; // sectors per track in the outermost zone - this->data_buf[27] = 1; // interleave factor - this->data_buf[29] = 19; // track skew factor - this->data_buf[31] = 25; // cylinder skew factor - this->data_buf[32] = 0x80; // SSEC=1, HSEC=0, RMB=0, SURF=0, INS=0 - WRITE_WORD_BE_U(&this->data_buf[24], 512); // bytes per sector - break; - case 0x30: // Copyright page for Apple certified drives - this->data_buf[13] = 22; // data size - 1 - std::memcpy(&this->data_buf[14], Apple_Copyright_Page_Data, 22); - break; - default: - ABORT_F("%s: unsupported page %d in MODE_SENSE_6", this->name.c_str(), page_code); - }; + WRITE_WORD_BE_U(&p_buf[ 2], 6); // tracks per defect zone + WRITE_WORD_BE_U(&p_buf[ 4], 1); // alternate sectors per zone + WRITE_WORD_BE_U(&p_buf[10], 92); // sectors per track in the outermost zone + WRITE_WORD_BE_U(&p_buf[12], 512); // bytes per sector + WRITE_WORD_BE_U(&p_buf[14], 1); // interleave factor + WRITE_WORD_BE_U(&p_buf[16], 19); // track skew factor + WRITE_WORD_BE_U(&p_buf[18], 25); // cylinder skew factor + p_buf[20] = 0x80; // SSEC=1, HSEC=0, RMB=0, SURF=0, INS=0 + p_buf += page_size; + got_page = true; + } + + if (page_code == 0x30 || page_code == 0x3f) { // Copyright page for Apple certified drives + if (sub_page_code != 0x00 && sub_page_code != 0xff) + goto bad_sub_page; + page_size = 24; + p_buf[0] = 0x30; // page code + p_buf[1] = page_size - 2; // data size - 1 + std::memcpy(&p_buf[2], Apple_Copyright_Page_Data, 22); + p_buf += page_size; + got_page = true; + } + + if (!(got_page || page_code == 0x3f)) { // not any of the supported pages or all pages + LOG_F(WARNING, "%s: unsupported page 0x%02x in MODE_SENSE_6", this->name.c_str(), page_code); + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = ScsiSense::ILLEGAL_REQ; + this->asc = 0x24; // Invalid Field in CDB + this->ascq = 0; + this->sksv = 0xc0; // sksv=1, C/D=Command, BPV=0, BP=0 + this->field = 2; + this->switch_phase(ScsiPhase::STATUS); + return; + bad_sub_page: + LOG_F(WARNING, "%s: unsupported page/subpage %02xh/%02xh in MODE_SENSE_6", this->name.c_str(), page_code, sub_page_code); + this->status = ScsiStatus::CHECK_CONDITION; + this->sense = ScsiSense::ILLEGAL_REQ; + this->asc = 0x24; // Invalid Field in CDB + this->ascq = 0; + this->sksv = 0xc0; // sksv=1, C/D=Command, BPV=0, BP=0 + this->field = 3; + this->switch_phase(ScsiPhase::STATUS); + return; + } // adjust for overall mode sense data length - this->data_buf[0] += this->data_buf[13] + 1; + this->data_buf[0] = p_buf - this->data_buf - 1; - this->bytes_out = std::min(alloc_len, (uint8_t)this->data_buf[0]); + this->bytes_out = std::min((int)alloc_len, (int)this->data_buf[0] + 1); this->switch_phase(ScsiPhase::DATA_IN); }