9cc0f23b09dcfd175a3ac40ce5e9c342209f453d
[SCSI2SD.git] / software / SCSI2SD / SCSI2SD.cydsn / inquiry.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\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
9 //\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
14 //\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
17 \r
18 #include "device.h"\r
19 #include "scsi.h"\r
20 #include "config.h"\r
21 #include "inquiry.h"\r
22 \r
23 #include <string.h>\r
24 \r
25 static uint8 StandardResponse[] =\r
26 {\r
27 0x00, // "Direct-access device". AKA standard hard disk\r
28 0x00, // device type qualifier\r
29 0x02, // Complies with ANSI SCSI-2.\r
30 0x02, // SCSI-2 Inquiry response\r
31 31, // standard length\r
32 0, 0, //Reserved\r
33 0 // We don't support anything at all\r
34 };\r
35 // Vendor set by config 'c','o','d','e','s','r','c',' ',\r
36 // prodId set by config'S','C','S','I','2','S','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',\r
37 // Revision set by config'2','.','0','a'\r
38 \r
39 static const uint8 SupportedVitalPages[] =\r
40 {\r
41 0x00, // "Direct-access device". AKA standard hard disk\r
42 0x00, // Page Code\r
43 0x00, // Reserved\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
49 };\r
50 \r
51 static const uint8 UnitSerialNumber[] =\r
52 {\r
53 0x00, // "Direct-access device". AKA standard hard disk\r
54 0x80, // Page Code\r
55 0x00, // Reserved\r
56 0x10, // Page length\r
57 'c','o','d','e','s','r','c','-','1','2','3','4','5','6','7','8'\r
58 };\r
59 \r
60 static const uint8 ImpOperatingDefinition[] =\r
61 {\r
62 0x00, // "Direct-access device". AKA standard hard disk\r
63 0x81, // Page Code\r
64 0x00, // Reserved\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
69 };\r
70 \r
71 static const uint8 AscImpOperatingDefinition[] =\r
72 {\r
73 0x00, // "Direct-access device". AKA standard hard disk\r
74 0x82, // Page Code\r
75 0x00, // Reserved\r
76 0x07, // Page length\r
77 0x06, // Ascii length\r
78 'S','C','S','I','-','2'\r
79 };\r
80 \r
81 void scsiInquiry()\r
82 {\r
83         uint8 evpd = scsiDev.cdb[1] & 1; // enable vital product data.\r
84         uint8 pageCode = scsiDev.cdb[2];\r
85         uint8 lun = scsiDev.cdb[1] >> 5;\r
86         uint32 allocationLength = scsiDev.cdb[4];\r
87         if (allocationLength == 0) allocationLength = 256;\r
88 \r
89         if (!evpd)\r
90         {\r
91                 if (pageCode)\r
92                 {\r
93                         // error.\r
94                         scsiDev.status = CHECK_CONDITION;\r
95                         scsiDev.sense.code = ILLEGAL_REQUEST;\r
96                         scsiDev.sense.asc = INVALID_FIELD_IN_CDB;\r
97                         scsiDev.phase = STATUS;\r
98                 }\r
99                 else\r
100                 {\r
101                         uint8* out;\r
102                         memcpy(scsiDev.data, StandardResponse, sizeof(StandardResponse));\r
103                         out = scsiDev.data + sizeof(StandardResponse);\r
104                         memcpy(out, config->vendor, sizeof(config->vendor));\r
105                         out += sizeof(config->vendor);\r
106                         memcpy(out, config->prodId, sizeof(config->prodId));\r
107                         out += sizeof(config->prodId);\r
108                         memcpy(out, config->revision, sizeof(config->revision));\r
109                         out += sizeof(config->revision);                        \r
110                         scsiDev.dataLen = out - scsiDev.data;\r
111                         scsiDev.phase = DATA_IN;\r
112                         \r
113                         if (!lun) scsiDev.unitAttention = 0;\r
114                 }\r
115         }\r
116         else if (pageCode == 0x00)\r
117         {\r
118                 memcpy(scsiDev.data, SupportedVitalPages, sizeof(SupportedVitalPages));\r
119                 scsiDev.dataLen = sizeof(SupportedVitalPages);\r
120                 scsiDev.phase = DATA_IN;\r
121         }\r
122         else if (pageCode == 0x80)\r
123         {\r
124                 memcpy(scsiDev.data, UnitSerialNumber, sizeof(UnitSerialNumber));\r
125                 scsiDev.dataLen = sizeof(UnitSerialNumber);\r
126                 scsiDev.phase = DATA_IN;\r
127         }\r
128         else if (pageCode == 0x81)\r
129         {\r
130                 memcpy(\r
131                         scsiDev.data,\r
132                         ImpOperatingDefinition,\r
133                         sizeof(ImpOperatingDefinition));\r
134                 scsiDev.dataLen = sizeof(ImpOperatingDefinition);\r
135                 scsiDev.phase = DATA_IN;\r
136         }\r
137         else if (pageCode == 0x82)\r
138         {\r
139                 memcpy(\r
140                         scsiDev.data,\r
141                         AscImpOperatingDefinition,\r
142                         sizeof(AscImpOperatingDefinition));\r
143                 scsiDev.dataLen = sizeof(AscImpOperatingDefinition);\r
144                 scsiDev.phase = DATA_IN;\r
145         }\r
146         else\r
147         {\r
148                 // error.\r
149                 scsiDev.status = CHECK_CONDITION;\r
150                 scsiDev.sense.code = ILLEGAL_REQUEST;\r
151                 scsiDev.sense.asc = INVALID_FIELD_IN_CDB;\r
152                 scsiDev.phase = STATUS;\r
153         }\r
154 \r
155 \r
156         if (scsiDev.phase == DATA_IN && scsiDev.dataLen > allocationLength)\r
157         {\r
158                 // Spec 8.2.5 requires us to simply truncate the response.\r
159                 scsiDev.dataLen = allocationLength;\r
160         }\r
161 \r
162 \r
163         // Set the first byte to indicate LUN presence.\r
164         if (lun) // We only support lun 0\r
165         {\r
166                 scsiDev.data[0] = 0x7F;\r
167         }\r
168 }\r
169 \r