9cc0f23b09dcfd175a3ac40ce5e9c342209f453d
[SCSI2SD.git] / software / SCSI2SD / SCSI2SD.cydsn / inquiry.c
1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
2 //
3 // This file is part of SCSI2SD.
4 //
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17
18 #include "device.h"
19 #include "scsi.h"
20 #include "config.h"
21 #include "inquiry.h"
22
23 #include <string.h>
24
25 static uint8 StandardResponse[] =
26 {
27 0x00, // "Direct-access device". AKA standard hard disk
28 0x00, // device type qualifier
29 0x02, // Complies with ANSI SCSI-2.
30 0x02, // SCSI-2 Inquiry response
31 31, // standard length
32 0, 0, //Reserved
33 0 // We don't support anything at all
34 };
35 // Vendor set by config 'c','o','d','e','s','r','c',' ',
36 // prodId set by config'S','C','S','I','2','S','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',
37 // Revision set by config'2','.','0','a'
38
39 static const uint8 SupportedVitalPages[] =
40 {
41 0x00, // "Direct-access device". AKA standard hard disk
42 0x00, // Page Code
43 0x00, // Reserved
44 0x04, // Page length
45 0x00, // Support "Supported vital product data pages"
46 0x80, // Support "Unit serial number page"
47 0x81, // Support "Implemented operating definition page"
48 0x82 // Support "ASCII Implemented operating definition page"
49 };
50
51 static const uint8 UnitSerialNumber[] =
52 {
53 0x00, // "Direct-access device". AKA standard hard disk
54 0x80, // Page Code
55 0x00, // Reserved
56 0x10, // Page length
57 'c','o','d','e','s','r','c','-','1','2','3','4','5','6','7','8'
58 };
59
60 static const uint8 ImpOperatingDefinition[] =
61 {
62 0x00, // "Direct-access device". AKA standard hard disk
63 0x81, // Page Code
64 0x00, // Reserved
65 0x03, // Page length
66 0x03, // Current: SCSI-2 operating definition
67 0x03, // Default: SCSI-2 operating definition
68 0x03 // Supported (list): SCSI-2 operating definition.
69 };
70
71 static const uint8 AscImpOperatingDefinition[] =
72 {
73 0x00, // "Direct-access device". AKA standard hard disk
74 0x82, // Page Code
75 0x00, // Reserved
76 0x07, // Page length
77 0x06, // Ascii length
78 'S','C','S','I','-','2'
79 };
80
81 void scsiInquiry()
82 {
83 uint8 evpd = scsiDev.cdb[1] & 1; // enable vital product data.
84 uint8 pageCode = scsiDev.cdb[2];
85 uint8 lun = scsiDev.cdb[1] >> 5;
86 uint32 allocationLength = scsiDev.cdb[4];
87 if (allocationLength == 0) allocationLength = 256;
88
89 if (!evpd)
90 {
91 if (pageCode)
92 {
93 // error.
94 scsiDev.status = CHECK_CONDITION;
95 scsiDev.sense.code = ILLEGAL_REQUEST;
96 scsiDev.sense.asc = INVALID_FIELD_IN_CDB;
97 scsiDev.phase = STATUS;
98 }
99 else
100 {
101 uint8* out;
102 memcpy(scsiDev.data, StandardResponse, sizeof(StandardResponse));
103 out = scsiDev.data + sizeof(StandardResponse);
104 memcpy(out, config->vendor, sizeof(config->vendor));
105 out += sizeof(config->vendor);
106 memcpy(out, config->prodId, sizeof(config->prodId));
107 out += sizeof(config->prodId);
108 memcpy(out, config->revision, sizeof(config->revision));
109 out += sizeof(config->revision);
110 scsiDev.dataLen = out - scsiDev.data;
111 scsiDev.phase = DATA_IN;
112
113 if (!lun) scsiDev.unitAttention = 0;
114 }
115 }
116 else if (pageCode == 0x00)
117 {
118 memcpy(scsiDev.data, SupportedVitalPages, sizeof(SupportedVitalPages));
119 scsiDev.dataLen = sizeof(SupportedVitalPages);
120 scsiDev.phase = DATA_IN;
121 }
122 else if (pageCode == 0x80)
123 {
124 memcpy(scsiDev.data, UnitSerialNumber, sizeof(UnitSerialNumber));
125 scsiDev.dataLen = sizeof(UnitSerialNumber);
126 scsiDev.phase = DATA_IN;
127 }
128 else if (pageCode == 0x81)
129 {
130 memcpy(
131 scsiDev.data,
132 ImpOperatingDefinition,
133 sizeof(ImpOperatingDefinition));
134 scsiDev.dataLen = sizeof(ImpOperatingDefinition);
135 scsiDev.phase = DATA_IN;
136 }
137 else if (pageCode == 0x82)
138 {
139 memcpy(
140 scsiDev.data,
141 AscImpOperatingDefinition,
142 sizeof(AscImpOperatingDefinition));
143 scsiDev.dataLen = sizeof(AscImpOperatingDefinition);
144 scsiDev.phase = DATA_IN;
145 }
146 else
147 {
148 // error.
149 scsiDev.status = CHECK_CONDITION;
150 scsiDev.sense.code = ILLEGAL_REQUEST;
151 scsiDev.sense.asc = INVALID_FIELD_IN_CDB;
152 scsiDev.phase = STATUS;
153 }
154
155
156 if (scsiDev.phase == DATA_IN && scsiDev.dataLen > allocationLength)
157 {
158 // Spec 8.2.5 requires us to simply truncate the response.
159 scsiDev.dataLen = allocationLength;
160 }
161
162
163 // Set the first byte to indicate LUN presence.
164 if (lun) // We only support lun 0
165 {
166 scsiDev.data[0] = 0x7F;
167 }
168 }
169