inquiry.c 4.7 KB

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