1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
\r
3 // This file is part of SCSI2SD.
\r
5 // SCSI2SD is free software: you can redistribute it and/or modify
\r
6 // it under the terms of the GNU General Public License as published by
\r
7 // the Free Software Foundation, either version 3 of the License, or
\r
8 // (at your option) any later version.
\r
10 // SCSI2SD is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
\r
20 #include "inquiry.h"
\r
24 static uint8_t StandardResponse[] =
\r
26 0x00, // "Direct-access device". AKA standard hard disk
\r
27 0x00, // device type modifier
\r
28 0x02, // Complies with ANSI SCSI-2.
\r
29 0x01, // Response format is compatible with the old CCS format.
\r
30 0x1f, // standard length.
\r
32 0x18 // Enable sync and linked commands
\r
34 // Vendor set by config 'c','o','d','e','s','r','c',' ',
\r
35 // prodId set by config'S','C','S','I','2','S','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',
\r
36 // Revision set by config'2','.','0','a'
\r
39 static const uint8_t SupportedVitalPages[] =
\r
41 0x00, // "Direct-access device". AKA standard hard disk
\r
44 0x04, // Page length
\r
45 0x00, // Support "Supported vital product data pages"
\r
46 0x80, // Support "Unit serial number page"
\r
47 0x81, // Support "Implemented operating definition page"
\r
48 0x82 // Support "ASCII Implemented operating definition page"
\r
51 static const uint8_t UnitSerialNumber[] =
\r
53 0x00, // "Direct-access device". AKA standard hard disk
\r
56 0x10, // Page length
\r
57 'c','o','d','e','s','r','c','-','1','2','3','4','5','6','7','8'
\r
60 static const uint8_t ImpOperatingDefinition[] =
\r
62 0x00, // "Direct-access device". AKA standard hard disk
\r
65 0x03, // Page length
\r
66 0x03, // Current: SCSI-2 operating definition
\r
67 0x03, // Default: SCSI-2 operating definition
\r
68 0x03 // Supported (list): SCSI-2 operating definition.
\r
71 static const uint8_t AscImpOperatingDefinition[] =
\r
73 0x00, // "Direct-access device". AKA standard hard disk
\r
76 0x07, // Page length
\r
77 0x06, // Ascii length
\r
78 'S','C','S','I','-','2'
\r
81 void s2s_scsiInquiry()
\r
83 uint8_t evpd = scsiDev.cdb[1] & 1; // enable vital product data.
\r
84 uint8_t pageCode = scsiDev.cdb[2];
\r
85 uint32_t allocationLength = scsiDev.cdb[4];
\r
87 // SASI standard, X3T9.3_185_RevE states that 0 == 256 bytes
\r
88 // BUT SCSI 2 standard says 0 == 0.
\r
89 if (scsiDev.compatMode <= COMPAT_SCSI1) // excludes COMPAT_SCSI2_DISABLED
\r
91 if (allocationLength == 0) allocationLength = 256;
\r
99 scsiDev.status = CHECK_CONDITION;
\r
100 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
101 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
102 scsiDev.phase = STATUS;
\r
106 const S2S_TargetCfg* config = scsiDev.target->cfg;
\r
108 s2s_getStandardInquiry(
\r
111 sizeof(scsiDev.data));
\r
112 scsiDev.phase = DATA_IN;
\r
115 else if (pageCode == 0x00)
\r
117 memcpy(scsiDev.data, SupportedVitalPages, sizeof(SupportedVitalPages));
\r
118 scsiDev.dataLen = sizeof(SupportedVitalPages);
\r
119 scsiDev.phase = DATA_IN;
\r
121 else if (pageCode == 0x80)
\r
123 memcpy(scsiDev.data, UnitSerialNumber, sizeof(UnitSerialNumber));
\r
124 scsiDev.dataLen = sizeof(UnitSerialNumber);
\r
125 scsiDev.phase = DATA_IN;
\r
127 else if (pageCode == 0x81)
\r
131 ImpOperatingDefinition,
\r
132 sizeof(ImpOperatingDefinition));
\r
133 scsiDev.dataLen = sizeof(ImpOperatingDefinition);
\r
134 scsiDev.phase = DATA_IN;
\r
136 else if (pageCode == 0x82)
\r
140 AscImpOperatingDefinition,
\r
141 sizeof(AscImpOperatingDefinition));
\r
142 scsiDev.dataLen = sizeof(AscImpOperatingDefinition);
\r
143 scsiDev.phase = DATA_IN;
\r
148 scsiDev.status = CHECK_CONDITION;
\r
149 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
150 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
151 scsiDev.phase = STATUS;
\r
155 if (scsiDev.phase == DATA_IN)
\r
157 // "real" hard drives send back exactly allocationLenth bytes, padded
\r
158 // with zeroes. This only seems to happen for Inquiry responses, and not
\r
159 // other commands that also supply an allocation length such as Mode Sense or
\r
161 // (See below for exception to this rule when 0 allocation length)
\r
162 if (scsiDev.dataLen < allocationLength)
\r
165 &scsiDev.data[scsiDev.dataLen],
\r
167 allocationLength - scsiDev.dataLen);
\r
169 // Spec 8.2.5 requires us to simply truncate the response if it's
\r
171 scsiDev.dataLen = allocationLength;
\r
173 // Set the device type as needed.
\r
174 switch (scsiDev.target->cfg->deviceType)
\r
176 case S2S_CFG_OPTICAL:
\r
177 scsiDev.data[0] = 0x05; // device type
\r
178 scsiDev.data[1] |= 0x80; // Removable bit.
\r
181 case S2S_CFG_SEQUENTIAL:
\r
182 scsiDev.data[0] = 0x01; // device type
\r
183 scsiDev.data[1] |= 0x80; // Removable bit.
\r
187 scsiDev.data[0] = 0x07; // device type
\r
188 scsiDev.data[1] |= 0x80; // Removable bit.
\r
191 case S2S_CFG_FLOPPY_14MB:
\r
192 case S2S_CFG_REMOVEABLE:
\r
193 scsiDev.data[1] |= 0x80; // Removable bit.
\r
196 // Accept defaults for a fixed disk.
\r
201 // Set the first byte to indicate LUN presence.
\r
202 if (scsiDev.lun) // We only support lun 0
\r
204 scsiDev.data[0] = 0x7F;
\r
208 uint32_t s2s_getStandardInquiry(
\r
209 const S2S_TargetCfg* cfg, uint8_t* out, uint32_t maxlen
\r
212 uint32_t buflen = sizeof(StandardResponse);
\r
213 if (buflen > maxlen) buflen = maxlen;
\r
215 memcpy(out, StandardResponse, buflen);
\r
216 out[1] = cfg->deviceTypeModifier;
\r
218 if (scsiDev.compatMode >= COMPAT_SCSI2)
\r
220 out[3] = 2; // SCSI 2 response format.
\r
222 memcpy(&out[8], cfg->vendor, sizeof(cfg->vendor));
\r
223 memcpy(&out[16], cfg->prodId, sizeof(cfg->prodId));
\r
224 memcpy(&out[32], cfg->revision, sizeof(cfg->revision));
\r
225 return sizeof(StandardResponse) +
\r
226 sizeof(cfg->vendor) +
\r
227 sizeof(cfg->prodId) +
\r
228 sizeof(cfg->revision);
\r