/* We won't be needing this... */ uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser * prs) { #if MS_WANT_PARSER if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA; Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80); Notify(PSTR("---------\r\n"), 0x80); CommandBlockWrapper cbw = CommandBlockWrapper(); cbw.dCBWSignature = MASS_CBW_SIGNATURE; cbw.dCBWTag = ++dCBWTag; cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); cbw.bmCBWFlags = MASS_CMD_DIR_IN, cbw.bmCBWLUN = lun; cbw.bmCBWCBLength = 10; cbw.CBWCB[0] = SCSI_CMD_READ_10; cbw.CBWCB[8] = blocks; cbw.CBWCB[2] = ((addr >> 24) & 0xff); cbw.CBWCB[3] = ((addr >> 16) & 0xff); cbw.CBWCB[4] = ((addr >> 8) & 0xff); cbw.CBWCB[5] = (addr & 0xff); return HandleSCSIError(Transaction(&cbw, bsize, prs, 1)); #else return MASS_ERR_NOT_IMPLEMENTED; #endif }
/** * Media control, for spindle motor and media tray or door. * This includes CDROM, TAPE and anything with a media loader. * * @param lun Logical Unit Number * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media * @return 0 on success */ uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) { Notify(PSTR("\r\nMediaCTL\r\n"), 0x80); Notify(PSTR("-----------------\r\n"), 0x80); SetCurLUN(lun); uint8_t rcode = MASS_ERR_UNIT_NOT_READY; if (bAddress) { CommandBlockWrapper cbw; cbw.dCBWSignature = MASS_CBW_SIGNATURE; cbw.dCBWTag = ++dCBWTag; cbw.dCBWDataTransferLength = 0; cbw.bmCBWFlags = MASS_CMD_DIR_OUT; cbw.bmCBWLUN = lun; cbw.bmCBWCBLength = 6; for (uint8_t i = 0; i < 16; i++) cbw.CBWCB[i] = 0; cbw.CBWCB[0] = SCSI_CMD_START_STOP_UNIT; cbw.CBWCB[1] = lun << 5; cbw.CBWCB[4] = ctl & 0x03; rcode = HandleSCSIError(Transaction(&cbw, 0, NULL, 0)); } return rcode; }
/** * For driver use only. Used during Driver Init * * @param lun Logical Unit Number * @param bsize * @param buf * @return */ uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) { Notify(PSTR("\r\nInquiry\r\n"), 0x80); Notify(PSTR("---------\r\n"), 0x80); CommandBlockWrapper cbw; SetCurLUN(lun); cbw.dCBWSignature = MASS_CBW_SIGNATURE; cbw.dCBWTag = ++dCBWTag; cbw.dCBWDataTransferLength = bsize; cbw.bmCBWFlags = MASS_CMD_DIR_IN; cbw.bmCBWLUN = lun; cbw.bmCBWCBLength = 6; for (uint8_t i = 0; i < 16; i++) cbw.CBWCB[i] = 0; cbw.CBWCB[0] = SCSI_CMD_INQUIRY; cbw.CBWCB[1] = lun << 5; cbw.CBWCB[4] = bsize; uint8_t rc = HandleSCSIError(Transaction(&cbw, bsize, buf, 0)); #if 0 if (!rc) { printf("LUN %i `", lun); for (int i = 8; i < 36; i++) printf("%c", buf[i]); printf("'\r\nQualifier %1.1X ", (buf[0]&0xE0) >> 5); printf("Device type %2.2X ", buf[0]&0x1f); printf("RMB %1.1X ", buf[1]&0x80 >> 7); printf("SSCS% 1.1X ", buf[5]&0x80 >> 7); uint8_t sv = buf[2]; printf("SCSI version %2.2X\r\nDevice conforms to ", sv); switch (sv) { case 0: printf("No specific"); break; /* case 1: printf(""); break; */ case 2: printf("ANSI 2"); break; case 3: printf("ANSI INCITS 301-1997 (SPC)"); break; case 4: printf("ANSI INCITS 351-2001 (SPC-2)"); break; case 5: printf("ANSI INCITS 408-2005 (SPC-4)"); break; case 6: printf("T10/1731-D (SPC-4)"); break; default: printf("unknown"); } printf(" standards.\r\n"); }
/** * Write data to media * * @param lun Logical Unit Number * @param addr LBA address on media to write * @param bsize size of a block (we should probably use the cached size) * @param blocks how many blocks to write * @param buf memory that contains the data to write * @return 0 on success */ uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) { if (!LUNOk[lun]) return MASS_ERR_NO_MEDIA; if (!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED; Notify(PSTR("\r\nWrite LUN:\t"), 0x80); D_PrintHex<uint8_t > (lun, 0x90); //printf("LUN=%i LBA=%8.8X BLOCKS=%i SIZE=%i\r\n", lun, addr, blocks, bsize); Notify(PSTR("\r\nLBA:\t\t"), 0x90); D_PrintHex<uint32_t > (addr, 0x90); Notify(PSTR("\r\nblocks:\t\t"), 0x90); D_PrintHex<uint8_t > (blocks, 0x90); Notify(PSTR("\r\nblock size:\t"), 0x90); D_PrintHex<uint16_t > (bsize, 0x90); Notify(PSTR("\r\n---------\r\n"), 0x80); //MediaCTL(lun, 0x01); CommandBlockWrapper cbw; again: cbw.dCBWSignature = MASS_CBW_SIGNATURE; cbw.dCBWTag = ++dCBWTag; cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks); cbw.bmCBWFlags = MASS_CMD_DIR_OUT; cbw.bmCBWLUN = lun; cbw.bmCBWCBLength = 10; for (uint8_t i = 0; i < 16; i++) cbw.CBWCB[i] = 0; cbw.CBWCB[0] = SCSI_CMD_WRITE_10; cbw.CBWCB[1] = lun << 5; cbw.CBWCB[2] = ((addr >> 24) & 0xff); cbw.CBWCB[3] = ((addr >> 16) & 0xff); cbw.CBWCB[4] = ((addr >> 8) & 0xff); cbw.CBWCB[5] = (addr & 0xff); cbw.CBWCB[8] = 1; SetCurLUN(lun); uint8_t er = HandleSCSIError(Transaction(&cbw, bsize, (void*)buf, 0)); if (er == MASS_ERR_WRITE_STALL) { MediaCTL(lun, 1); delay(150); if (!TestUnitReady(lun)) goto again; } return er; }
/** * Lock or Unlock the tray or door on device. * Caution: Some devices with buggy firmware will lock up. * * @param lun Logical Unit Number * @param lock 1 to lock, 0 to unlock * @return */ uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) { Notify(PSTR("\r\nLockMedia\r\n"), 0x80); Notify(PSTR("---------\r\n"), 0x80); CommandBlockWrapper cbw; SetCurLUN(lun); cbw.dCBWSignature = MASS_CBW_SIGNATURE; cbw.dCBWTag = ++dCBWTag; cbw.dCBWDataTransferLength = 0; cbw.bmCBWFlags = MASS_CMD_DIR_IN; cbw.bmCBWLUN = lun; cbw.bmCBWCBLength = 6; for (uint8_t i = 0; i < 16; i++) cbw.CBWCB[i] = 0; cbw.CBWCB[0] = SCSI_CMD_PREVENT_REMOVAL; cbw.CBWCB[4] = lock; return (HandleSCSIError(Transaction(&cbw, 0, NULL, 0))); }
/** * Wrap and execute a SCSI CDB with length of 10 * * @param cdb CDB to execute * @param buf_size Size of expected transaction * @param buf Buffer * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT * @return */ uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { // promote buf_size to 32bits. CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); //SetCurLUN(cdb->LUN); return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); }