inquiry.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
  2. // Copyright (C) 2019 Landon Rodgers <g.landon.rodgers@gmail.com>
  3. //
  4. // This file is part of SCSI2SD.
  5. //
  6. // SCSI2SD is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // SCSI2SD is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
  18. #include "scsi.h"
  19. #include "config.h"
  20. #include "BlueSCSI_config.h"
  21. #include "inquiry.h"
  22. #include <string.h>
  23. static uint8_t StandardResponse[] =
  24. {
  25. 0x00, // "Direct-access device". AKA standard hard disk
  26. 0x00, // device type modifier
  27. 0x02, // Complies with ANSI SCSI-2.
  28. 0x01, // Response format is compatible with the old CCS format.
  29. 0x1f, // standard length.
  30. 0, 0, // Reserved
  31. 0x18 // Enable sync and linked commands
  32. };
  33. // Vendor set by config 'c','o','d','e','s','r','c',' ',
  34. // prodId set by config'S','C','S','I','2','S','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',
  35. // Revision set by config'2','.','0','a'
  36. static const uint8_t SupportedVitalPages[] =
  37. {
  38. 0x00, // "Direct-access device". AKA standard hard disk
  39. 0x00, // Page Code
  40. 0x00, // Reserved
  41. 0x04, // Page length
  42. 0x00, // Support "Supported vital product data pages"
  43. 0x80, // Support "Unit serial number page"
  44. 0x81, // Support "Implemented operating definition page"
  45. 0x82 // Support "ASCII Implemented operating definition page"
  46. };
  47. static const uint8_t UnitSerialNumber[] =
  48. {
  49. 0x00, // "Direct-access device". AKA standard hard disk
  50. 0x80, // Page Code
  51. 0x00, // Reserved
  52. 0x10, // Page length
  53. 'c','o','d','e','s','r','c','-','1','2','3','4','5','6','7','8'
  54. };
  55. static const uint8_t ImpOperatingDefinition[] =
  56. {
  57. 0x00, // "Direct-access device". AKA standard hard disk
  58. 0x81, // Page Code
  59. 0x00, // Reserved
  60. 0x03, // Page length
  61. 0x03, // Current: SCSI-2 operating definition
  62. 0x03, // Default: SCSI-2 operating definition
  63. 0x03 // Supported (list): SCSI-2 operating definition.
  64. };
  65. static const uint8_t AscImpOperatingDefinition[] =
  66. {
  67. 0x00, // "Direct-access device". AKA standard hard disk
  68. 0x82, // Page Code
  69. 0x00, // Reserved
  70. 0x07, // Page length
  71. 0x06, // Ascii length
  72. 'S','C','S','I','-','2'
  73. };
  74. void s2s_scsiInquiry()
  75. {
  76. uint8_t evpd = scsiDev.cdb[1] & 1; // enable vital product data.
  77. uint8_t pageCode = scsiDev.cdb[2];
  78. uint32_t allocationLength = scsiDev.cdb[4];
  79. // SASI standard, X3T9.3_185_RevE states that 0 == 256 bytes
  80. // BUT SCSI 2 standard says 0 == 0.
  81. if (scsiDev.compatMode <= COMPAT_SCSI1) // excludes COMPAT_SCSI2_DISABLED
  82. {
  83. if (allocationLength == 0) allocationLength = 256;
  84. }
  85. if (!evpd)
  86. {
  87. if (pageCode)
  88. {
  89. // error.
  90. scsiDev.status = CHECK_CONDITION;
  91. scsiDev.target->sense.code = ILLEGAL_REQUEST;
  92. scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
  93. scsiDev.phase = STATUS;
  94. }
  95. else
  96. {
  97. const S2S_TargetCfg* config = scsiDev.target->cfg;
  98. scsiDev.dataLen =
  99. s2s_getStandardInquiry(
  100. config,
  101. scsiDev.data,
  102. sizeof(scsiDev.data));
  103. scsiDev.phase = DATA_IN;
  104. }
  105. }
  106. else if (pageCode == 0x00)
  107. {
  108. memcpy(scsiDev.data, SupportedVitalPages, sizeof(SupportedVitalPages));
  109. scsiDev.dataLen = sizeof(SupportedVitalPages);
  110. scsiDev.phase = DATA_IN;
  111. }
  112. else if (pageCode == 0x80)
  113. {
  114. memcpy(scsiDev.data, UnitSerialNumber, sizeof(UnitSerialNumber));
  115. scsiDev.dataLen = sizeof(UnitSerialNumber);
  116. const S2S_TargetCfg* config = scsiDev.target->cfg;
  117. memcpy(&scsiDev.data[4], config->serial, sizeof(config->serial));
  118. scsiDev.phase = DATA_IN;
  119. }
  120. else if (pageCode == 0x81)
  121. {
  122. memcpy(
  123. scsiDev.data,
  124. ImpOperatingDefinition,
  125. sizeof(ImpOperatingDefinition));
  126. scsiDev.dataLen = sizeof(ImpOperatingDefinition);
  127. scsiDev.phase = DATA_IN;
  128. }
  129. else if (pageCode == 0x82)
  130. {
  131. memcpy(
  132. scsiDev.data,
  133. AscImpOperatingDefinition,
  134. sizeof(AscImpOperatingDefinition));
  135. scsiDev.dataLen = sizeof(AscImpOperatingDefinition);
  136. scsiDev.phase = DATA_IN;
  137. }
  138. else
  139. {
  140. // error.
  141. scsiDev.status = CHECK_CONDITION;
  142. scsiDev.target->sense.code = ILLEGAL_REQUEST;
  143. scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
  144. scsiDev.phase = STATUS;
  145. }
  146. if (scsiDev.phase == DATA_IN)
  147. {
  148. // VAX workaround
  149. if (allocationLength == 255 &&
  150. (scsiDev.target->cfg->quirks & S2S_CFG_QUIRKS_VMS))
  151. {
  152. allocationLength = 254;
  153. }
  154. // "real" hard drives send back exactly allocationLenth bytes, padded
  155. // with zeroes. This only seems to happen for Inquiry responses, and not
  156. // other commands that also supply an allocation length such as Mode Sense or
  157. // Request Sense.
  158. // (See below for exception to this rule when 0 allocation length)
  159. if (scsiDev.dataLen < allocationLength)
  160. {
  161. memset(
  162. &scsiDev.data[scsiDev.dataLen],
  163. 0,
  164. allocationLength - scsiDev.dataLen);
  165. }
  166. // Spec 8.2.5 requires us to simply truncate the response if it's
  167. // too big.
  168. scsiDev.dataLen = allocationLength;
  169. // Set the device type as needed.
  170. scsiDev.data[0] = getDeviceTypeQualifier();
  171. switch (scsiDev.target->cfg->deviceType)
  172. {
  173. case S2S_CFG_OPTICAL:
  174. scsiDev.data[1] |= 0x80; // Removable bit.
  175. break;
  176. case S2S_CFG_SEQUENTIAL:
  177. scsiDev.data[1] |= 0x80; // Removable bit.
  178. break;
  179. case S2S_CFG_MO:
  180. scsiDev.data[1] |= 0x80; // Removable bit.
  181. break;
  182. case S2S_CFG_FLOPPY_14MB:
  183. case S2S_CFG_REMOVEABLE:
  184. scsiDev.data[1] |= 0x80; // Removable bit.
  185. break;
  186. case S2S_CFG_NETWORK:
  187. scsiDev.data[2] = 0x01; // Page code.
  188. break;
  189. default:
  190. // Accept defaults for a fixed disk.
  191. break;
  192. }
  193. }
  194. // Set the first byte to indicate LUN presence.
  195. if (scsiDev.lun) // We only support lun 0
  196. {
  197. scsiDev.data[0] = 0x7F;
  198. }
  199. }
  200. uint32_t s2s_getStandardInquiry(
  201. const S2S_TargetCfg* cfg, uint8_t* out, uint32_t maxlen
  202. )
  203. {
  204. uint32_t size = 0;
  205. uint32_t buflen = sizeof(StandardResponse);
  206. if (buflen > maxlen) buflen = maxlen;
  207. memcpy(out, StandardResponse, buflen);
  208. out[1] = cfg->deviceTypeModifier;
  209. if (!(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SCSI2))
  210. {
  211. out[2] = 1; // Report only SCSI 1 compliance version
  212. }
  213. if (scsiDev.compatMode >= COMPAT_SCSI2)
  214. {
  215. out[3] = 2; // SCSI 2 response format.
  216. }
  217. memcpy(&out[8], cfg->vendor, sizeof(cfg->vendor));
  218. memcpy(&out[16], cfg->prodId, sizeof(cfg->prodId));
  219. memcpy(&out[32], cfg->revision, sizeof(cfg->revision));
  220. size = sizeof(StandardResponse) +
  221. sizeof(cfg->vendor) +
  222. sizeof(cfg->prodId) +
  223. sizeof(cfg->revision);
  224. // Mac Daynaport Driver does not like this added.
  225. if(cfg->deviceType != S2S_CFG_NETWORK) {
  226. memcpy(&out[36], PLATFORM_INQUIRY, sizeof(PLATFORM_INQUIRY));
  227. size += sizeof(PLATFORM_INQUIRY);
  228. }
  229. return size;
  230. }
  231. uint8_t getDeviceTypeQualifier()
  232. {
  233. // Set the device type as needed.
  234. switch (scsiDev.target->cfg->deviceType)
  235. {
  236. case S2S_CFG_OPTICAL:
  237. return 0x05;
  238. break;
  239. case S2S_CFG_SEQUENTIAL:
  240. return 0x01;
  241. break;
  242. case S2S_CFG_MO:
  243. return 0x07;
  244. break;
  245. case S2S_CFG_FLOPPY_14MB:
  246. case S2S_CFG_REMOVEABLE:
  247. return 0;
  248. break;
  249. case S2S_CFG_NETWORK:
  250. // processor device
  251. return 0x03;
  252. break;
  253. default:
  254. // Accept defaults for a fixed disk.
  255. return 0;
  256. }
  257. }