Many bug fixes, including selection fixes.
[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 0x01, // Response format is compatible with the old CCS format.\r
31 0x1f, // 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 /* For reference, here's a dump from an Apple branded 500Mb drive from 1994.\r
40 $ sudo sg_inq -H /dev/sdd --len 255\r
41 standard INQUIRY:\r
42  00     00 00 02 01 31 00 00 18  51 55 41 4e 54 55 4d 20    ....1...QUANTUM \r
43  10     4c 50 53 32 37 30 20 20  20 20 20 20 20 20 20 20    LPS270          \r
44  20     30 39 30 30 00 00 00 d9  b0 27 34 01 04 b3 01 1b    0900.....'4.....\r
45  30     07 00 a0 00 00 ff                                   ......\r
46  Vendor identification: QUANTUM \r
47  Product identification: LPS270          \r
48  Product revision level: 0900\r
49 */\r
50 \r
51 \r
52 static const uint8 SupportedVitalPages[] =\r
53 {\r
54 0x00, // "Direct-access device". AKA standard hard disk\r
55 0x00, // Page Code\r
56 0x00, // Reserved\r
57 0x04, // Page length\r
58 0x00, // Support "Supported vital product data pages"\r
59 0x80, // Support "Unit serial number page"\r
60 0x81, // Support "Implemented operating definition page"\r
61 0x82 // Support "ASCII Implemented operating definition page"\r
62 };\r
63 \r
64 static const uint8 UnitSerialNumber[] =\r
65 {\r
66 0x00, // "Direct-access device". AKA standard hard disk\r
67 0x80, // Page Code\r
68 0x00, // Reserved\r
69 0x10, // Page length\r
70 'c','o','d','e','s','r','c','-','1','2','3','4','5','6','7','8'\r
71 };\r
72 \r
73 static const uint8 ImpOperatingDefinition[] =\r
74 {\r
75 0x00, // "Direct-access device". AKA standard hard disk\r
76 0x81, // Page Code\r
77 0x00, // Reserved\r
78 0x03, // Page length\r
79 0x03, // Current: SCSI-2 operating definition\r
80 0x03, // Default: SCSI-2 operating definition\r
81 0x03 // Supported (list): SCSI-2 operating definition.\r
82 };\r
83 \r
84 static const uint8 AscImpOperatingDefinition[] =\r
85 {\r
86 0x00, // "Direct-access device". AKA standard hard disk\r
87 0x82, // Page Code\r
88 0x00, // Reserved\r
89 0x07, // Page length\r
90 0x06, // Ascii length\r
91 'S','C','S','I','-','2'\r
92 };\r
93 \r
94 void scsiInquiry()\r
95 {\r
96         uint8 evpd = scsiDev.cdb[1] & 1; // enable vital product data.\r
97         uint8 pageCode = scsiDev.cdb[2];\r
98         uint8 lun = scsiDev.cdb[1] >> 5;\r
99         uint32 allocationLength = scsiDev.cdb[4];\r
100         if (allocationLength == 0) allocationLength = 256;\r
101         \r
102         if (!evpd)\r
103         {\r
104                 if (pageCode)\r
105                 {\r
106                         // error.\r
107                         scsiDev.status = CHECK_CONDITION;\r
108                         scsiDev.sense.code = ILLEGAL_REQUEST;\r
109                         scsiDev.sense.asc = INVALID_FIELD_IN_CDB;\r
110                         scsiDev.phase = STATUS;\r
111                 }\r
112                 else\r
113                 {\r
114                         memcpy(scsiDev.data, StandardResponse, sizeof(StandardResponse));\r
115                         memcpy(&scsiDev.data[8], config->vendor, sizeof(config->vendor));\r
116                         memcpy(&scsiDev.data[16], config->prodId, sizeof(config->prodId));\r
117                         memcpy(&scsiDev.data[32], config->revision, sizeof(config->revision));\r
118                         scsiDev.dataLen = sizeof(StandardResponse) +\r
119                                 sizeof(config->vendor) +\r
120                                 sizeof(config->prodId) +\r
121                                 sizeof(config->revision);\r
122                         scsiDev.phase = DATA_IN;\r
123                         \r
124                         if (!lun) scsiDev.unitAttention = 0;\r
125                 }\r
126         }\r
127         else if (pageCode == 0x00)\r
128         {\r
129                 memcpy(scsiDev.data, SupportedVitalPages, sizeof(SupportedVitalPages));\r
130                 scsiDev.dataLen = sizeof(SupportedVitalPages);\r
131                 scsiDev.phase = DATA_IN;\r
132         }\r
133         else if (pageCode == 0x80)\r
134         {\r
135                 memcpy(scsiDev.data, UnitSerialNumber, sizeof(UnitSerialNumber));\r
136                 scsiDev.dataLen = sizeof(UnitSerialNumber);\r
137                 scsiDev.phase = DATA_IN;\r
138         }\r
139         else if (pageCode == 0x81)\r
140         {\r
141                 memcpy(\r
142                         scsiDev.data,\r
143                         ImpOperatingDefinition,\r
144                         sizeof(ImpOperatingDefinition));\r
145                 scsiDev.dataLen = sizeof(ImpOperatingDefinition);\r
146                 scsiDev.phase = DATA_IN;\r
147         }\r
148         else if (pageCode == 0x82)\r
149         {\r
150                 memcpy(\r
151                         scsiDev.data,\r
152                         AscImpOperatingDefinition,\r
153                         sizeof(AscImpOperatingDefinition));\r
154                 scsiDev.dataLen = sizeof(AscImpOperatingDefinition);\r
155                 scsiDev.phase = DATA_IN;\r
156         }\r
157         else\r
158         {\r
159                 // error.\r
160                 scsiDev.status = CHECK_CONDITION;\r
161                 scsiDev.sense.code = ILLEGAL_REQUEST;\r
162                 scsiDev.sense.asc = INVALID_FIELD_IN_CDB;\r
163                 scsiDev.phase = STATUS;\r
164         }\r
165 \r
166 \r
167         if (scsiDev.phase == DATA_IN)\r
168         {\r
169                 // "real" hard drives send back exactly allocationLenth bytes, padded\r
170                 // with zeroes. This only seems to happen for Inquiry responses, and not\r
171                 // other commands that also supply an allocation length such as Mode Sense or\r
172                 // Request Sense.\r
173                 if (scsiDev.dataLen < allocationLength)\r
174                 {\r
175                         memset(\r
176                                 &scsiDev.data[scsiDev.dataLen],\r
177                                 0,\r
178                                 allocationLength - scsiDev.dataLen);\r
179                 }\r
180                 // Spec 8.2.5 requires us to simply truncate the response if it's too big.\r
181                 scsiDev.dataLen = allocationLength;\r
182         }\r
183 \r
184         // Set the first byte to indicate LUN presence.\r
185         if (lun) // We only support lun 0\r
186         {\r
187                 scsiDev.data[0] = 0x7F;\r
188         }\r
189 }\r
190 \r