disk.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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 "disk.h"
  21. #include "sd.h"
  22. #include <string.h>
  23. // Global
  24. BlockDevice blockDev;
  25. Transfer transfer;
  26. static int doSdInit()
  27. {
  28. int result = sdInit();
  29. if (result)
  30. {
  31. blockDev.state = blockDev.state | DISK_INITIALISED;
  32. // artificially limit this value according to EEPROM config.
  33. blockDev.capacity =
  34. (config->maxBlocks && (sdDev.capacity > config->maxBlocks))
  35. ? config->maxBlocks : sdDev.capacity;
  36. }
  37. return result;
  38. }
  39. static void doFormatUnit()
  40. {
  41. // Low-level formatting is not required.
  42. // Nothing left to do.
  43. }
  44. static void doReadCapacity()
  45. {
  46. uint32 lba = (((uint32) scsiDev.cdb[2]) << 24) +
  47. (((uint32) scsiDev.cdb[3]) << 16) +
  48. (((uint32) scsiDev.cdb[4]) << 8) +
  49. scsiDev.cdb[5];
  50. int pmi = scsiDev.cdb[8] & 1;
  51. if (!pmi && lba)
  52. {
  53. // error.
  54. // We don't do anything with the "partial medium indicator", and
  55. // assume that delays are constant across each block. But the spec
  56. // says we must return this error if pmi is specified incorrectly.
  57. scsiDev.status = CHECK_CONDITION;
  58. scsiDev.sense.code = ILLEGAL_REQUEST;
  59. scsiDev.sense.asc = INVALID_FIELD_IN_CDB;
  60. scsiDev.phase = STATUS;
  61. }
  62. else if (blockDev.capacity > 0)
  63. {
  64. uint32 highestBlock = blockDev.capacity - 1;
  65. scsiDev.data[0] = highestBlock >> 24;
  66. scsiDev.data[1] = highestBlock >> 16;
  67. scsiDev.data[2] = highestBlock >> 8;
  68. scsiDev.data[3] = highestBlock;
  69. scsiDev.data[4] = blockDev.bs >> 24;
  70. scsiDev.data[5] = blockDev.bs >> 16;
  71. scsiDev.data[6] = blockDev.bs >> 8;
  72. scsiDev.data[7] = blockDev.bs;
  73. scsiDev.dataLen = 8;
  74. scsiDev.phase = DATA_IN;
  75. }
  76. else
  77. {
  78. scsiDev.status = CHECK_CONDITION;
  79. scsiDev.sense.code = NOT_READY;
  80. scsiDev.sense.asc = MEDIUM_NOT_PRESENT;
  81. scsiDev.phase = STATUS;
  82. }
  83. }
  84. static void doWrite(uint32 lba, uint32 blocks)
  85. {
  86. if (blockDev.state & DISK_WP)
  87. {
  88. scsiDev.status = CHECK_CONDITION;
  89. scsiDev.sense.code = ILLEGAL_REQUEST;
  90. scsiDev.sense.asc = WRITE_PROTECTED;
  91. scsiDev.phase = STATUS;
  92. }
  93. else if (((uint64) lba) + blocks > blockDev.capacity)
  94. {
  95. scsiDev.status = CHECK_CONDITION;
  96. scsiDev.sense.code = ILLEGAL_REQUEST;
  97. scsiDev.sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
  98. scsiDev.phase = STATUS;
  99. }
  100. else
  101. {
  102. transfer.dir = TRANSFER_WRITE;
  103. transfer.lba = lba;
  104. transfer.blocks = blocks;
  105. transfer.currentBlock = 0;
  106. scsiDev.phase = DATA_OUT;
  107. scsiDev.dataLen = SCSI_BLOCK_SIZE;
  108. scsiDev.dataPtr = SCSI_BLOCK_SIZE; // TODO FIX scsiDiskPoll()
  109. // No need for single-block reads atm. Overhead of the
  110. // multi-block read is minimal.
  111. transfer.multiBlock = 1;
  112. sdPrepareWrite();
  113. }
  114. }
  115. static void doRead(uint32 lba, uint32 blocks)
  116. {
  117. if (((uint64) lba) + blocks > blockDev.capacity)
  118. {
  119. scsiDev.status = CHECK_CONDITION;
  120. scsiDev.sense.code = ILLEGAL_REQUEST;
  121. scsiDev.sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
  122. scsiDev.phase = STATUS;
  123. }
  124. else
  125. {
  126. transfer.dir = TRANSFER_READ;
  127. transfer.lba = lba;
  128. transfer.blocks = blocks;
  129. transfer.currentBlock = 0;
  130. scsiDev.phase = DATA_IN;
  131. scsiDev.dataLen = 0; // No data yet
  132. if ((blocks == 1) ||
  133. (((uint64) lba) + blocks == blockDev.capacity)
  134. )
  135. {
  136. // We get errors on reading the last sector using a multi-sector
  137. // read :-(
  138. transfer.multiBlock = 0;
  139. }
  140. else
  141. {
  142. transfer.multiBlock = 1;
  143. sdPrepareRead();
  144. }
  145. }
  146. }
  147. static void doSeek(uint32 lba)
  148. {
  149. if (lba >= blockDev.capacity)
  150. {
  151. scsiDev.status = CHECK_CONDITION;
  152. scsiDev.sense.code = ILLEGAL_REQUEST;
  153. scsiDev.sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
  154. scsiDev.phase = STATUS;
  155. }
  156. }
  157. static int doTestUnitReady()
  158. {
  159. int ready = 1;
  160. if (!(blockDev.state & DISK_STARTED))
  161. {
  162. ready = 0;
  163. scsiDev.status = CHECK_CONDITION;
  164. scsiDev.sense.code = NOT_READY;
  165. scsiDev.sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;
  166. scsiDev.phase = STATUS;
  167. }
  168. else if (!(blockDev.state & DISK_PRESENT))
  169. {
  170. ready = 0;
  171. scsiDev.status = CHECK_CONDITION;
  172. scsiDev.sense.code = NOT_READY;
  173. scsiDev.sense.asc = MEDIUM_NOT_PRESENT;
  174. scsiDev.phase = STATUS;
  175. }
  176. else if (!(blockDev.state & DISK_INITIALISED))
  177. {
  178. ready = 0;
  179. scsiDev.status = CHECK_CONDITION;
  180. scsiDev.sense.code = NOT_READY;
  181. scsiDev.sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;
  182. scsiDev.phase = STATUS;
  183. }
  184. return ready;
  185. }
  186. // Handle direct-access scsi device commands
  187. int scsiDiskCommand()
  188. {
  189. int commandHandled = 1;
  190. uint8 command = scsiDev.cdb[0];
  191. if (command == 0x1B)
  192. {
  193. // START STOP UNIT
  194. // Enable or disable media access operations.
  195. // Ignore load/eject requests. We can't do that.
  196. //int immed = scsiDev.cdb[1] & 1;
  197. int start = scsiDev.cdb[4] & 1;
  198. if (start)
  199. {
  200. blockDev.state = blockDev.state | DISK_STARTED;
  201. if (!(blockDev.state & DISK_INITIALISED))
  202. {
  203. doSdInit();
  204. }
  205. }
  206. else
  207. {
  208. blockDev.state &= ~DISK_STARTED;
  209. }
  210. }
  211. else if (command == 0x00)
  212. {
  213. // TEST UNIT READY
  214. doTestUnitReady();
  215. }
  216. else if (!doTestUnitReady())
  217. {
  218. // Status and sense codes already set by doTestUnitReady
  219. }
  220. else if (command == 0x04)
  221. {
  222. // FORMAT UNIT
  223. doFormatUnit();
  224. }
  225. else if (command == 0x08)
  226. {
  227. // READ(6)
  228. uint32 lba =
  229. (((uint32) scsiDev.cdb[1] & 0x1F) << 16) +
  230. (((uint32) scsiDev.cdb[2]) << 8) +
  231. scsiDev.cdb[3];
  232. uint32 blocks = scsiDev.cdb[4];
  233. if (blocks == 0) blocks = 256;
  234. doRead(lba, blocks);
  235. }
  236. else if (command == 0x28)
  237. {
  238. // READ(10)
  239. // Ignore all cache control bits - we don't support a memory cache.
  240. uint32 lba =
  241. (((uint32) scsiDev.cdb[2]) << 24) +
  242. (((uint32) scsiDev.cdb[3]) << 16) +
  243. (((uint32) scsiDev.cdb[4]) << 8) +
  244. scsiDev.cdb[5];
  245. uint32 blocks =
  246. (((uint32) scsiDev.cdb[7]) << 8) +
  247. scsiDev.cdb[8];
  248. doRead(lba, blocks);
  249. }
  250. else if (command == 0x25)
  251. {
  252. // READ CAPACITY
  253. doReadCapacity();
  254. }
  255. else if (command == 0x0B)
  256. {
  257. // SEEK(6)
  258. uint32 lba =
  259. (((uint32) scsiDev.cdb[1] & 0x1F) << 16) +
  260. (((uint32) scsiDev.cdb[2]) << 8) +
  261. scsiDev.cdb[3];
  262. doSeek(lba);
  263. }
  264. else if (command == 0x2B)
  265. {
  266. // SEEK(10)
  267. uint32 lba =
  268. (((uint32) scsiDev.cdb[2]) << 24) +
  269. (((uint32) scsiDev.cdb[3]) << 16) +
  270. (((uint32) scsiDev.cdb[4]) << 8) +
  271. scsiDev.cdb[5];
  272. doSeek(lba);
  273. }
  274. else if (command == 0x0A)
  275. {
  276. // WRITE(6)
  277. uint32 lba =
  278. (((uint32) scsiDev.cdb[1] & 0x1F) << 16) +
  279. (((uint32) scsiDev.cdb[2]) << 8) +
  280. scsiDev.cdb[3];
  281. uint32 blocks = scsiDev.cdb[4];
  282. if (blocks == 0) blocks = 256;
  283. doWrite(lba, blocks);
  284. }
  285. else if (command == 0x2A)
  286. {
  287. // WRITE(10)
  288. // Ignore all cache control bits - we don't support a memory cache.
  289. uint32 lba =
  290. (((uint32) scsiDev.cdb[2]) << 24) +
  291. (((uint32) scsiDev.cdb[3]) << 16) +
  292. (((uint32) scsiDev.cdb[4]) << 8) +
  293. scsiDev.cdb[5];
  294. uint32 blocks =
  295. (((uint32) scsiDev.cdb[7]) << 8) +
  296. scsiDev.cdb[8];
  297. doWrite(lba, blocks);
  298. }
  299. else if (command == 0x36)
  300. {
  301. // LOCK UNLOCK CACHE
  302. // We don't have a cache to lock data into. do nothing.
  303. }
  304. else if (command == 0x34)
  305. {
  306. // PRE-FETCH.
  307. // We don't have a cache to pre-fetch into. do nothing.
  308. }
  309. else if (command == 0x1E)
  310. {
  311. // PREVENT ALLOW MEDIUM REMOVAL
  312. // Not much we can do to prevent the user removing the SD card.
  313. // do nothing.
  314. }
  315. else if (command == 0x01)
  316. {
  317. // REZERO UNIT
  318. // Set the lun to a vendor-specific state. Ignore.
  319. }
  320. else if (command == 0x35)
  321. {
  322. // SYNCHRONIZE CACHE
  323. // We don't have a cache. do nothing.
  324. }
  325. else
  326. {
  327. commandHandled = 0;
  328. }
  329. return commandHandled;
  330. }
  331. void scsiDiskPoll()
  332. {
  333. if (scsiDev.phase == DATA_IN &&
  334. transfer.currentBlock != transfer.blocks)
  335. {
  336. if (scsiDev.dataLen == 0)
  337. {
  338. if (transfer.multiBlock)
  339. {
  340. sdReadSectorMulti();
  341. }
  342. else
  343. {
  344. sdReadSectorSingle();
  345. }
  346. }
  347. else if (scsiDev.dataPtr == scsiDev.dataLen)
  348. {
  349. scsiDev.dataLen = 0;
  350. scsiDev.dataPtr = 0;
  351. transfer.currentBlock++;
  352. if (transfer.currentBlock >= transfer.blocks)
  353. {
  354. int needComplete = transfer.multiBlock;
  355. scsiDev.phase = STATUS;
  356. scsiDiskReset();
  357. if (needComplete)
  358. {
  359. sdCompleteRead();
  360. }
  361. }
  362. }
  363. }
  364. else if (scsiDev.phase == DATA_OUT &&
  365. transfer.currentBlock != transfer.blocks)
  366. {
  367. int writeOk = sdWriteSector();
  368. // TODO FIX scsiDiskPoll() scsiDev.dataPtr = 0;
  369. transfer.currentBlock++;
  370. if (transfer.currentBlock >= transfer.blocks)
  371. {
  372. scsiDev.dataLen = 0;
  373. scsiDev.dataPtr = 0;
  374. scsiDev.phase = STATUS;
  375. scsiDiskReset();
  376. if (writeOk)
  377. {
  378. sdCompleteWrite();
  379. }
  380. }
  381. }
  382. }
  383. void scsiDiskReset()
  384. {
  385. // todo if SPI command in progress, cancel it.
  386. scsiDev.dataPtr = 0;
  387. scsiDev.savedDataPtr = 0;
  388. scsiDev.dataLen = 0;
  389. transfer.lba = 0;
  390. transfer.blocks = 0;
  391. transfer.currentBlock = 0;
  392. transfer.multiBlock = 0;
  393. }
  394. void scsiDiskInit()
  395. {
  396. blockDev.bs = SCSI_BLOCK_SIZE;
  397. blockDev.capacity = 0;
  398. scsiDiskReset();
  399. // Don't require the host to send us a START STOP UNIT command
  400. blockDev.state = DISK_STARTED;
  401. // WP pin not available for micro-sd
  402. // TODO read card WP register
  403. #if 0
  404. if (SD_WP_Read())
  405. {
  406. blockDev.state = blockDev.state | DISK_WP;
  407. }
  408. #endif
  409. if (SD_CD_Read() == 1)
  410. {
  411. int retry;
  412. blockDev.state = blockDev.state | DISK_PRESENT;
  413. // Wait up to 5 seconds for the SD card to wake up.
  414. for (retry = 0; retry < 5; ++retry)
  415. {
  416. if (doSdInit())
  417. {
  418. break;
  419. }
  420. else
  421. {
  422. CyDelay(1000);
  423. }
  424. }
  425. }
  426. }