diff options
Diffstat (limited to 'os/various')
-rw-r--r-- | os/various/bitmap.h | 6 | ||||
-rw-r--r-- | os/various/dbgtrace.h | 41 | ||||
-rw-r--r-- | os/various/fatfs_bindings/fatfs.mk | 7 | ||||
-rw-r--r-- | os/various/fatfs_bindings/fatfs_diskio.c | 320 | ||||
-rw-r--r-- | os/various/jlink.mk | 4 | ||||
-rw-r--r-- | os/various/lib_scsi.c | 548 | ||||
-rw-r--r-- | os/various/lib_scsi.h | 293 | ||||
-rw-r--r-- | os/various/ramdisk.c | 219 | ||||
-rw-r--r-- | os/various/ramdisk.h | 86 | ||||
-rw-r--r-- | os/various/tribuf.h | 6 |
10 files changed, 1524 insertions, 6 deletions
diff --git a/os/various/bitmap.h b/os/various/bitmap.h index d7831aa..115b54c 100644 --- a/os/various/bitmap.h +++ b/os/various/bitmap.h @@ -22,8 +22,8 @@ * @{ */ -#ifndef _BITMAP_H_ -#define _BITMAP_H_ +#ifndef BITMAP_H_ +#define BITMAP_H_ /*===========================================================================*/ /* Module constants. */ @@ -72,6 +72,6 @@ extern "C" { } #endif -#endif /* _BITMAP_H_ */ +#endif /* BITMAP_H_ */ /** @} */ diff --git a/os/various/dbgtrace.h b/os/various/dbgtrace.h new file mode 100644 index 0000000..b1fc297 --- /dev/null +++ b/os/various/dbgtrace.h @@ -0,0 +1,41 @@ +#ifndef DBGTRACE_H_ +#define DBGTRACE_H_ + +#include "chprintf.h" + +#if !defined(DEBUG_TRACE_PRINT) +#define DEBUG_TRACE_PRINT FALSE +#endif + +#if !defined(DEBUG_TRACE_WARNING) +#define DEBUG_TRACE_WARNING FALSE +#endif + +#if !defined(DEBUG_TRACE_ERROR) +#define DEBUG_TRACE_ERROR FALSE +#endif + +/* user must provide correctly initialized pointer to print channel */ +#if DEBUG_TRACE_PRINT || DEBUG_TRACE_WARNING || DEBUG_TRACE_ERROR +extern BaseSequentialStream *GlobalDebugChannel; +#endif + +#if DEBUG_TRACE_PRINT +#define dbgprintf(fmt, ...) chprintf(GlobalDebugChannel, fmt, ##__VA_ARGS__) +#else +#define dbgprintf(fmt, ...) do {} while(0) +#endif + +#if DEBUG_TRACE_WARNING +#define warnprintf(fmt, ...) chprintf(GlobalDebugChannel, fmt, ##__VA_ARGS__) +#else +#define warnprintf(fmt, ...) do {} while(0) +#endif + +#if DEBUG_TRACE_ERROR +#define errprintf(fmt, ...) chprintf(GlobalDebugChannel, fmt, ##__VA_ARGS__) +#else +#define errprintf(fmt, ...) do {} while(0) +#endif + +#endif /* DBGTRACE_H_ */ diff --git a/os/various/fatfs_bindings/fatfs.mk b/os/various/fatfs_bindings/fatfs.mk new file mode 100644 index 0000000..f2feeb5 --- /dev/null +++ b/os/various/fatfs_bindings/fatfs.mk @@ -0,0 +1,7 @@ +# FATFS files. +FATFSSRC = ${CHIBIOS_CONTRIB}/os/various/fatfs_bindings/fatfs_diskio.c \ + ${CHIBIOS}/os/various/fatfs_bindings/fatfs_syscall.c \ + ${CHIBIOS}/ext/fatfs/src/ff.c \ + $(CHIBIOS)/ext/fatfs/src/ffunicode.c + +FATFSINC = ${CHIBIOS}/ext/fatfs/src diff --git a/os/various/fatfs_bindings/fatfs_diskio.c b/os/various/fatfs_bindings/fatfs_diskio.c new file mode 100644 index 0000000..80d1502 --- /dev/null +++ b/os/various/fatfs_bindings/fatfs_diskio.c @@ -0,0 +1,320 @@ +/*-----------------------------------------------------------------------*/ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */ +/*-----------------------------------------------------------------------*/ +/* This is a stub disk I/O module that acts as front end of the existing */ +/* disk I/O modules and attach it to FatFs module with common interface. */ +/*-----------------------------------------------------------------------*/ + +#include "hal.h" +#include "ffconf.h" +#include "diskio.h" +#include "usbh/dev/msd.h" + +#if HAL_USE_MMC_SPI && HAL_USE_SDC +#error "cannot specify both MMC_SPI and SDC drivers" +#endif + +#if HAL_USE_MMC_SPI +extern MMCDriver MMCD1; +#elif HAL_USE_SDC +extern SDCDriver SDCD1; +#elif HAL_USBH_USE_MSD + +#else +#error "MMC_SPI, SDC or USBH_MSD driver must be specified" +#endif + +/*-----------------------------------------------------------------------*/ +/* Correspondence between physical drive number and physical drive. */ +#if HAL_USE_MMC_SPI +#define MMC 0 +#endif + +#if HAL_USE_SDC +#define SDC 0 +#endif + +#if HAL_USBH_USE_MSD +#if defined(MMC) || defined(SDC) +#define MSDLUN0 1 +#else +#define MSDLUN0 0 +#endif +#endif + +/*-----------------------------------------------------------------------*/ +/* Inidialize a Drive */ + +DSTATUS disk_initialize ( + BYTE pdrv /* Physical drive nmuber (0..) */ +) +{ + DSTATUS stat; + + switch (pdrv) { +#if HAL_USE_MMC_SPI + case MMC: + stat = 0; + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&MMCD1) != BLK_READY) + stat |= STA_NOINIT; + if (mmcIsWriteProtected(&MMCD1)) + stat |= STA_PROTECT; + return stat; +#elif HAL_USE_SDC + case SDC: + stat = 0; + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&SDCD1) != BLK_READY) + stat |= STA_NOINIT; + if (sdcIsWriteProtected(&SDCD1)) + stat |= STA_PROTECT; + return stat; +#endif +#if HAL_USBH_USE_MSD + case MSDLUN0: + stat = 0; + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&MSBLKD[0]) != BLK_READY) + stat |= STA_NOINIT; + return stat; +#endif + } + return STA_NOINIT; +} + + + +/*-----------------------------------------------------------------------*/ +/* Return Disk Status */ + +DSTATUS disk_status ( + BYTE pdrv /* Physical drive number (0..) */ +) +{ + DSTATUS stat; + + switch (pdrv) { +#if HAL_USE_MMC_SPI + case MMC: + stat = 0; + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&MMCD1) != BLK_READY) + stat |= STA_NOINIT; + if (mmcIsWriteProtected(&MMCD1)) + stat |= STA_PROTECT; + return stat; +#elif HAL_USE_SDC + case SDC: + stat = 0; + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&SDCD1) != BLK_READY) + stat |= STA_NOINIT; + if (sdcIsWriteProtected(&SDCD1)) + stat |= STA_PROTECT; + return stat; +#endif +#if HAL_USBH_USE_MSD + case MSDLUN0: + stat = 0; + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&MSBLKD[0]) != BLK_READY) + stat |= STA_NOINIT; + return stat; +#endif + } + return STA_NOINIT; +} + + + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ + +DRESULT disk_read ( + BYTE pdrv, /* Physical drive number (0..) */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Sector address (LBA) */ + UINT count /* Number of sectors to read (1..255) */ +) +{ + switch (pdrv) { +#if HAL_USE_MMC_SPI + case MMC: + if (blkGetDriverState(&MMCD1) != BLK_READY) + return RES_NOTRDY; + if (mmcStartSequentialRead(&MMCD1, sector)) + return RES_ERROR; + while (count > 0) { + if (mmcSequentialRead(&MMCD1, buff)) + return RES_ERROR; + buff += MMCSD_BLOCK_SIZE; + count--; + } + if (mmcStopSequentialRead(&MMCD1)) + return RES_ERROR; + return RES_OK; +#elif HAL_USE_SDC + case SDC: + if (blkGetDriverState(&SDCD1) != BLK_READY) + return RES_NOTRDY; + if (sdcRead(&SDCD1, sector, buff, count)) + return RES_ERROR; + return RES_OK; +#endif +#if HAL_USBH_USE_MSD + case MSDLUN0: + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&MSBLKD[0]) != BLK_READY) + return RES_NOTRDY; + if (usbhmsdLUNRead(&MSBLKD[0], sector, buff, count)) + return RES_ERROR; + return RES_OK; +#endif + } + return RES_PARERR; +} + + + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ + +DRESULT disk_write ( + BYTE pdrv, /* Physical drive number (0..) */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Sector address (LBA) */ + UINT count /* Number of sectors to write (1..255) */ +) +{ + switch (pdrv) { +#if HAL_USE_MMC_SPI + case MMC: + if (blkGetDriverState(&MMCD1) != BLK_READY) + return RES_NOTRDY; + if (mmcIsWriteProtected(&MMCD1)) + return RES_WRPRT; + if (mmcStartSequentialWrite(&MMCD1, sector)) + return RES_ERROR; + while (count > 0) { + if (mmcSequentialWrite(&MMCD1, buff)) + return RES_ERROR; + buff += MMCSD_BLOCK_SIZE; + count--; + } + if (mmcStopSequentialWrite(&MMCD1)) + return RES_ERROR; + return RES_OK; +#elif HAL_USE_SDC + case SDC: + if (blkGetDriverState(&SDCD1) != BLK_READY) + return RES_NOTRDY; + if (sdcWrite(&SDCD1, sector, buff, count)) + return RES_ERROR; + return RES_OK; +#endif +#if HAL_USBH_USE_MSD + case MSDLUN0: + /* It is initialized externally, just reads the status.*/ + if (blkGetDriverState(&MSBLKD[0]) != BLK_READY) + return RES_NOTRDY; + if (usbhmsdLUNWrite(&MSBLKD[0], sector, buff, count)) + return RES_ERROR; + return RES_OK; +#endif + } + return RES_PARERR; +} + + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ + +DRESULT disk_ioctl ( + BYTE pdrv, /* Physical drive number (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + switch (pdrv) { +#if HAL_USE_MMC_SPI + case MMC: + switch (cmd) { + case CTRL_SYNC: + return RES_OK; +#if _MAX_SS > _MIN_SS + case GET_SECTOR_SIZE: + *((WORD *)buff) = MMCSD_BLOCK_SIZE; + return RES_OK; +#endif +#if _USE_TRIM + case CTRL_TRIM: + mmcErase(&MMCD1, *((DWORD *)buff), *((DWORD *)buff + 1)); + return RES_OK; +#endif + default: + return RES_PARERR; + } +#elif HAL_USE_SDC + case SDC: + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + case GET_SECTOR_COUNT: + *((DWORD *)buff) = mmcsdGetCardCapacity(&SDCD1); + return RES_OK; +#if _MAX_SS > _MIN_SS + case GET_SECTOR_SIZE: + *((WORD *)buff) = MMCSD_BLOCK_SIZE; + return RES_OK; +#endif + case GET_BLOCK_SIZE: + *((DWORD *)buff) = 256; /* 512b blocks in one erase block */ + return RES_OK; +#if _USE_TRIM + case CTRL_TRIM: + sdcErase(&SDCD1, *((DWORD *)buff), *((DWORD *)buff + 1)); + return RES_OK; +#endif + default: + return RES_PARERR; + } +#endif +#if HAL_USBH_USE_MSD + case MSDLUN0: + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + case GET_SECTOR_COUNT: + *((DWORD *)buff) = MSBLKD[0].info.blk_num; + return RES_OK; +#if _MAX_SS > _MIN_SS + case GET_SECTOR_SIZE: + *((WORD *)buff) = MSBLKD[0].info.blk_size; + return RES_OK; +#endif +#if _USE_TRIM +#error "unimplemented yet!" +// case CTRL_TRIM: +// .... +// return RES_OK; +#endif + default: + return RES_PARERR; + } +#endif + } + return RES_PARERR; +} + +DWORD get_fattime(void) { +#if HAL_USE_RTC + RTCDateTime timespec; + + rtcGetTime(&RTCD1, ×pec); + return rtcConvertDateTimeToFAT(×pec); +#else + return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */ +#endif +} diff --git a/os/various/jlink.mk b/os/various/jlink.mk index 1a13bd3..00fedb3 100644 --- a/os/various/jlink.mk +++ b/os/various/jlink.mk @@ -27,6 +27,10 @@ jlink-reset: printf "r\nexit\n" > $(BUILDDIR)/reset.jlink $(JLINK) $(JLINK_COMMON_OPTS) $(BUILDDIR)/reset.jlink +jlink-pin-reset: + printf "$(JLINK_PIN_RESET)\nexit\n" > $(BUILDDIR)/pin-reset.jlink + $(JLINK) $(JLINK_COMMON_OPTS) $(BUILDDIR)/pin-reset.jlink + jlink-debug-server: $(JLINK_GDB_SERVER) $(JLINK_COMMON_OPTS) -port $(JLINK_GDB_PORT) diff --git a/os/various/lib_scsi.c b/os/various/lib_scsi.c new file mode 100644 index 0000000..720a90f --- /dev/null +++ b/os/various/lib_scsi.c @@ -0,0 +1,548 @@ +/* + ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file lib_scsi.c + * @brief SCSI target driver source code. + * + * @addtogroup SCSI + * @{ + */ + +#include <string.h> + +#include "hal.h" + +#include "lib_scsi.h" + +#define DEBUG_TRACE_PRINT FALSE +#define DEBUG_TRACE_WARNING FALSE +#define DEBUG_TRACE_ERROR FALSE +#include "dbgtrace.h" + +#define ARCH_LITTLE_ENDIAN +#include "bswap.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +typedef struct { + uint32_t first_lba; + uint16_t blk_cnt; +} data_request_t; + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Combines data request from byte array. + * + * @notapi + */ +static data_request_t decode_data_request(const uint8_t *cmd) { + + data_request_t req; + uint32_t lba; + uint16_t blk; + + memcpy(&lba, &cmd[2], sizeof(lba)); + memcpy(&blk, &cmd[7], sizeof(blk)); + + req.first_lba = be32_to_cpu(lba); + req.blk_cnt = be16_to_cpu(blk); + + return req; +} + +/** + * @brief Fills sense structure. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] key SCSI sense key + * @param[in] code SCSI sense code + * @param[in] qual SCSI sense qualifier + * + * @notapi + */ +static void set_sense(SCSITarget *scsip, uint8_t key, + uint8_t code, uint8_t qual) { + + scsi_sense_response_t *sense = &scsip->sense; + memset(sense, 0 , sizeof(scsi_sense_response_t)); + + sense->byte[0] = 0x70; + sense->byte[2] = key; + sense->byte[7] = 8; + sense->byte[12] = code; + sense->byte[13] = qual; +} + +/** + * @brief Sets all values in sense data to 'success' condition. + * + * @param[in] scsip pointer to @p SCSITarget structure + * + * @notapi + */ +static void set_sense_ok(SCSITarget *scsip) { + set_sense(scsip, SCSI_SENSE_KEY_GOOD, + SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, + SCSI_ASENSEQ_NO_QUALIFIER); +} + +/** + * @brief Transmits data via transport channel. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] data pointer to data buffer + * @param[in] len number of bytes to be transmitted + * + * @return The operation status. + * + * @notapi + */ +static bool transmit_data(SCSITarget *scsip, const uint8_t *data, uint32_t len) { + + const SCSITransport *trp = scsip->config->transport; + const uint32_t residue = len - trp->transmit(trp, data, len); + + if (residue > 0) { + scsip->residue = residue; + return SCSI_FAILED; + } + else { + return SCSI_SUCCESS; + } +} + +/** + * @brief Stub for unhandled SCSI commands. + * @details Sets error flags in sense data structure and returns error error. + */ +static bool cmd_unhandled(SCSITarget *scsip, const uint8_t *cmd) { + (void)cmd; + + set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_COMMAND, + SCSI_ASENSEQ_NO_QUALIFIER); + return SCSI_FAILED; +} + +/** + * @brief Stub for unrealized but required SCSI commands. + * @details Sets sense data in 'all OK' condition and returns success status. + */ +static bool cmd_ignored(SCSITarget *scsip, const uint8_t *cmd) { + (void)scsip; + (void)cmd; + + return SCSI_SUCCESS; +} + +/** + * @brief SCSI inquiry command handler. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @notapi + */ +static bool inquiry(SCSITarget *scsip, const uint8_t *cmd) { + + if ((cmd[1] & 0b1) && cmd[2] == 0x80) { + /* Unit serial number page */ + return transmit_data(scsip, (const uint8_t *)scsip->config->unit_serial_number_inquiry_response, + sizeof(scsi_unit_serial_number_inquiry_response_t)); + } + else if ((cmd[1] & 0b11) || cmd[2] != 0) { + set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_FIELD_IN_CDB, + SCSI_ASENSEQ_NO_QUALIFIER); + return SCSI_FAILED; + } + else { + return transmit_data(scsip, (const uint8_t *)scsip->config->inquiry_response, + sizeof(scsi_inquiry_response_t)); + } +} + +/** + * @brief SCSI request sense command handler. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @notapi + */ +static bool request_sense(SCSITarget *scsip, const uint8_t *cmd) { + + if (((cmd[1] & 0x01) != 0) || (cmd[4] != sizeof(scsi_sense_response_t))) { + set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_INVALID_FIELD_IN_CDB, + SCSI_ASENSEQ_NO_QUALIFIER); + return SCSI_FAILED; + } + else { + return transmit_data(scsip, (uint8_t *)&scsip->sense, + sizeof(scsi_sense_response_t)); + } +} + +/** + * @brief SCSI mode sense (6) command handler. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @notapi + */ +static bool mode_sense6(SCSITarget *scsip, const uint8_t *cmd) { + (void)cmd; + + scsip->mode_sense.byte[0] = sizeof(scsi_mode_sense6_response_t) - 1; + scsip->mode_sense.byte[1] = 0; + if (blkIsWriteProtected(scsip->config->blkdev)) { + scsip->mode_sense.byte[2] = 0x01 << 7; + } + else { + scsip->mode_sense.byte[2] = 0; + } + scsip->mode_sense.byte[3] = 0; + + return transmit_data(scsip, (uint8_t *)&scsip->mode_sense, + sizeof(scsi_mode_sense6_response_t)); +} + +/** + * @brief SCSI read format capacities command handler. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @notapi + */ +static bool read_format_capacities(SCSITarget *scsip, const uint8_t *cmd) { + + /* An Allocation Length of zero indicates that no data shall be transferred. + This condition shall not be considered as an error. The Logical Unit + shall terminate the data transfer when Allocation Length bytes have + been transferred or when all available data have been transferred to + the Initiator, whatever is less. */ + + uint16_t len = cmd[7] << 8 | cmd[8]; + + if (0 == len) { + return SCSI_SUCCESS; + } + else { + scsi_read_format_capacities_response_t ret; + BlockDeviceInfo bdi; + blkGetInfo(scsip->config->blkdev, &bdi); + + uint32_t tmp = cpu_to_be32(bdi.blk_num); + memcpy(ret.blocknum, &tmp, 4); + + uint8_t formatted_media = 0b10; + uint16_t blocklen = bdi.blk_size; + ret.blocklen[0] = formatted_media; + ret.blocklen[1] = 0; + ret.blocklen[2] = blocklen >> 8; + ret.blocklen[3] = blocklen & 0xFF; + + ret.header[3] = 1 * 8; + + return transmit_data(scsip, (uint8_t *)&ret, + sizeof(scsi_read_format_capacities_response_t)); + } +} + +/** + * @brief SCSI read capacity (10) command handler. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @notapi + */ +static bool read_capacity10(SCSITarget *scsip, const uint8_t *cmd) { + + (void)cmd; + + BlockDeviceInfo bdi; + blkGetInfo(scsip->config->blkdev, &bdi); + scsi_read_capacity10_response_t ret; + ret.block_size = cpu_to_be32(bdi.blk_size); + ret.last_block_addr = cpu_to_be32(bdi.blk_num - 1); + + return transmit_data(scsip, (uint8_t *)&ret, + sizeof(scsi_read_capacity10_response_t)); +} + +/** + * @brief Checks data request for media overflow. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * @retval true When media overflow detected. + * @retval false Otherwise. + * + * @notapi + */ +static bool data_overflow(SCSITarget *scsip, const data_request_t *req) { + + BlockDeviceInfo bdi; + blkGetInfo(scsip->config->blkdev, &bdi); + + if (req->first_lba + req->blk_cnt > bdi.blk_num) { + set_sense(scsip, SCSI_SENSE_KEY_ILLEGAL_REQUEST, + SCSI_ASENSE_LBA_OUT_OF_RANGE, + SCSI_ASENSEQ_NO_QUALIFIER); + return true; + } + else { + return false; + } +} + +/** + * @brief SCSI read/write (10) command handler. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @notapi + */ +static bool data_read_write10(SCSITarget *scsip, const uint8_t *cmd) { + + data_request_t req = decode_data_request(cmd); + + if (data_overflow(scsip, &req)) { + return SCSI_FAILED; + } + else { + const SCSITransport *tr = scsip->config->transport; + BaseBlockDevice *blkdev = scsip->config->blkdev; + BlockDeviceInfo bdi; + blkGetInfo(blkdev, &bdi); + size_t bs = bdi.blk_size; + uint8_t *buf = scsip->config->blkbuf; + + size_t i = 0; + for (i=0; i<req.blk_cnt; i++) { + if (cmd[0] == SCSI_CMD_READ_10) { + // TODO: block error handling + blkRead(blkdev, req.first_lba + i, buf, 1); + tr->transmit(tr, buf, bs); + } + else { + // TODO: block error handling + tr->receive(tr, buf, bs); + blkWrite(blkdev, req.first_lba + i, buf, 1); + } + } + } + return SCSI_SUCCESS; +} + +/** + * @brief SCSI test unit ready command handler + * @details If block device is inserted, sets sense data in 'all OK' condition + * and returns success status. + * If block device is not inserted, sets sense data to 'Medium not present' considion, + * and returns check condition status. + */ +static bool test_unit_ready(SCSITarget *scsip, const uint8_t *cmd) { + (void)cmd; + + if (blkIsInserted(scsip->config->blkdev)) { + return SCSI_SUCCESS; + } + else { + warnprintf("SCSI Medium is not inserted.\r\n"); + set_sense(scsip, SCSI_SENSE_KEY_NOT_READY, + SCSI_ASENSE_MEDIUM_NOT_PRESENT, + SCSI_ASENSEQ_NO_QUALIFIER); + return SCSI_FAILED; + } + +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Executes SCSI command encoded in byte array. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] cmd pointer to SCSI command data + * + * @return The operation status. + * + * @api + */ +bool scsiExecCmd(SCSITarget *scsip, const uint8_t *cmd) { + + bool ret = SCSI_SUCCESS; + + switch (cmd[0]) { + case SCSI_CMD_INQUIRY: + dbgprintf("SCSI_CMD_INQUIRY\r\n"); + ret = inquiry(scsip, cmd); + break; + + case SCSI_CMD_REQUEST_SENSE: + dbgprintf("SCSI_CMD_REQUEST_SENSE\r\n"); + ret = request_sense(scsip, cmd); + break; + + case SCSI_CMD_READ_CAPACITY_10: + dbgprintf("SCSI_CMD_READ_CAPACITY_10\r\n"); + ret = read_capacity10(scsip, cmd); + break; + + case SCSI_CMD_READ_10: + dbgprintf("SCSI_CMD_READ_10\r\n"); + ret = data_read_write10(scsip, cmd); + break; + + case SCSI_CMD_WRITE_10: + dbgprintf("SCSI_CMD_WRITE_10\r\n"); + ret = data_read_write10(scsip, cmd); + break; + + case SCSI_CMD_TEST_UNIT_READY: + dbgprintf("SCSI_CMD_TEST_UNIT_READY\r\n"); + ret = test_unit_ready(scsip, cmd); + break; + + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + dbgprintf("SCSI_CMD_ALLOW_MEDIUM_REMOVAL\r\n"); + ret = cmd_ignored(scsip, cmd); + break; + + case SCSI_CMD_MODE_SENSE_6: + dbgprintf("SCSI_CMD_MODE_SENSE_6\r\n"); + ret = mode_sense6(scsip, cmd); + break; + + case SCSI_CMD_READ_FORMAT_CAPACITIES: + dbgprintf("SCSI_CMD_READ_FORMAT_CAPACITIES\r\n"); + ret = read_format_capacities(scsip, cmd); + break; + + case SCSI_CMD_VERIFY_10: + dbgprintf("SCSI_CMD_VERIFY_10\r\n"); + ret = cmd_ignored(scsip, cmd); + break; + + default: + warnprintf("SCSI unhandled command: %X\r\n", cmd[0]); + ret = cmd_unhandled(scsip, cmd); + break; + } + + if (ret == SCSI_SUCCESS) + set_sense_ok(scsip); + + return ret; +} + +/** + * @brief Driver structure initialization. + * + * @param[in] scsip pointer to @p SCSITarget structure + * + * @api + */ +void scsiObjectInit(SCSITarget *scsip) { + + scsip->config = NULL; + scsip->residue = 0; + memset(&scsip->sense, 0 , sizeof(scsi_sense_response_t)); + scsip->state = SCSI_TRGT_STOP; +} + +/** + * @brief Starts SCSITarget driver. + * + * @param[in] scsip pointer to @p SCSITarget structure + * @param[in] config pointer to @p SCSITargetConfig structure + * + * @api + */ +void scsiStart(SCSITarget *scsip, const SCSITargetConfig *config) { + + scsip->config = config; + scsip->state = SCSI_TRGT_READY; +} + +/** + * @brief Stops SCSITarget driver. + * + * @param[in] scsip pointer to @p SCSITarget structure + * + * @api + */ +void scsiStop(SCSITarget *scsip) { + + scsip->config = NULL; + scsip->state = SCSI_TRGT_STOP; +} + +/** + * @brief Retrieves residue bytes. + * + * @param[in] scsip pointer to @p SCSITarget structure + * + * @return Residue bytes. + * + * @api + */ +uint32_t scsiResidue(const SCSITarget *scsip) { + + return scsip->residue; +} + +/** @} */ diff --git a/os/various/lib_scsi.h b/os/various/lib_scsi.h new file mode 100644 index 0000000..8384ae3 --- /dev/null +++ b/os/various/lib_scsi.h @@ -0,0 +1,293 @@ +/* + ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file wdg_lld.h + * @brief WDG Driver subsystem low level driver header template. + * + * @addtogroup WDG + * @{ + */ + +#ifndef LIB_SCSI_H_ +#define LIB_SCSI_H_ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define SCSI_CMD_TEST_UNIT_READY 0x00 +#define SCSI_CMD_REQUEST_SENSE 0x03 +#define SCSI_CMD_INQUIRY 0x12 +#define SCSI_CMD_MODE_SENSE_6 0x1A +#define SCSI_CMD_START_STOP_UNIT 0x1B +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_CMD_READ_CAPACITY_10 0x25 +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 +#define SCSI_CMD_READ_10 0x28 +#define SCSI_CMD_WRITE_10 0x2A +#define SCSI_CMD_VERIFY_10 0x2F + +#define SCSI_SENSE_KEY_GOOD 0x00 +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 +#define SCSI_SENSE_KEY_NOT_READY 0x02 +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 +#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 +#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 +#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D +#define SCSI_SENSE_KEY_MISCOMPARE 0x0E + +#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 +#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 +#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 +#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 +#define SCSI_ASENSE_WRITE_PROTECTED 0x27 +#define SCSI_ASENSE_FORMAT_ERROR 0x31 +#define SCSI_ASENSE_INVALID_COMMAND 0x20 +#define SCSI_ASENSE_LBA_OUT_OF_RANGE 0x21 +#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A + +#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 +#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 +#define SCSI_ASENSEQ_INIT_COMMAND_REQUIRED 0x02 +#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 + +#define SCSI_SUCCESS HAL_SUCCESS +#define SCSI_FAILED HAL_FAILED + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a structure representing an SCSI target. + */ +typedef struct SCSITarget SCSITarget; + +/** + * @brief Type of a structure representing an SCSI transport. + */ +typedef struct SCSITransport SCSITransport; + +/** + * @brief State of SCSI target. + */ +typedef enum { + SCSI_TRGT_UNINIT = 0, + SCSI_TRGT_STOP, + SCSI_TRGT_READY, +} scsitrgtstate_t; + +/** + * @brief Represents SCSI sense data structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR { + uint8_t byte[18]; +} scsi_sense_response_t; + +/** + * @brief Represents SCSI inquiry response structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR { + uint8_t peripheral; + uint8_t removable; + uint8_t version; + uint8_t response_data_format; + uint8_t additional_length; + uint8_t sccstp; + uint8_t bqueetc; + uint8_t cmdque; + uint8_t vendorID[8]; + uint8_t productID[16]; + uint8_t productRev[4]; +} scsi_inquiry_response_t; + +/** + * @brief Represents SCSI unit serial number inquiry response structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR { + uint8_t peripheral; + uint8_t page_code; + uint8_t reserved; + uint8_t page_length; + uint8_t serianNumber[8]; +} scsi_unit_serial_number_inquiry_response_t; +/** + * @brief Represents SCSI mode sense (6) request structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR { + uint8_t byte[6]; +} scsi_mode_sense6_request_t; + +/** + * @brief Represents SCSI mode sense (6) response structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR{ + uint8_t byte[4]; +} scsi_mode_sense6_response_t; + +/** + * @brief Represents SCSI read capacity (10) response structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR { + uint32_t last_block_addr; + uint32_t block_size; +} scsi_read_capacity10_response_t; + +/** + * @brief Represents SCSI read format capacity response structure. + * @details See SCSI specification. + */ +typedef struct PACKED_VAR { + uint8_t header[4]; + uint8_t blocknum[4]; + uint8_t blocklen[4]; +} scsi_read_format_capacities_response_t; + +/** + * @brief Type of a SCSI transport transmit call. + * + * @param[in] usbp pointer to the @p SCSITransport object + * @param[in] data pointer to payload buffer + * @param[in] len payload length + */ +typedef uint32_t (*scsi_transport_transmit_t)(const SCSITransport *transport, + const uint8_t *data, size_t len); + +/** + * @brief Type of a SCSI transport transmit call. + * + * @param[in] usbp pointer to the @p SCSITransport object + * @param[out] data pointer to receive buffer + * @param[in] len number of bytes to be received + */ +typedef uint32_t (*scsi_transport_receive_t)(const SCSITransport *transport, + uint8_t *data, size_t len); + +/** + * @brief SCSI transport structure. + */ +struct SCSITransport { + /** + * @brief Transmit call provided by lower level driver. + */ + scsi_transport_transmit_t transmit; + /** + * @brief Receive call provided by lower level driver. + */ + scsi_transport_receive_t receive; + /** + * @brief Transport handler provided by lower level driver. + */ + void *handler; +}; + +/** + * @brief SCSI target config structure. + */ +typedef struct { + /** + * @brief Pointer to @p SCSITransport object. + */ + const SCSITransport *transport; + /** + * @brief Pointer to @p BaseBlockDevice object. + */ + BaseBlockDevice *blkdev; + /** + * @brief Pointer to data buffer for single block. + */ + uint8_t *blkbuf; + /** + * @brief Pointer to SCSI inquiry response object. + */ + const scsi_inquiry_response_t *inquiry_response; + /** + * @brief Pointer to SCSI unit serial number inquiry response object. + */ + const scsi_unit_serial_number_inquiry_response_t *unit_serial_number_inquiry_response; +} SCSITargetConfig; + +/** + * + */ +struct SCSITarget { + /** + * @brief Pointer to @p SCSITargetConfig object. + */ + const SCSITargetConfig *config; + /** + * @brief Target state. + */ + scsitrgtstate_t state; + /** + * @brief SCSI sense response structure. + */ + scsi_sense_response_t sense; + /** + * @brief SCSI mode sense (6) response structure. + */ + scsi_mode_sense6_response_t mode_sense; + /** + * @brief Residue bytes. + */ + uint32_t residue; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void scsiObjectInit(SCSITarget *scsip); + void scsiStart(SCSITarget *scsip, const SCSITargetConfig *config); + void scsiStop(SCSITarget *scsip); + bool scsiExecCmd(SCSITarget *scsip, const uint8_t *cmd); + uint32_t scsiResidue(const SCSITarget *scsip); +#ifdef __cplusplus +} +#endif + +#endif /* LIB_SCSI_H_ */ + +/** @} */ diff --git a/os/various/ramdisk.c b/os/various/ramdisk.c new file mode 100644 index 0000000..23bf658 --- /dev/null +++ b/os/various/ramdisk.c @@ -0,0 +1,219 @@ +/* + ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file ramdisk.c + * @brief Virtual block devise driver source. + * + * @addtogroup ramdisk + * @{ + */ + +#include "hal.h" + +#include "ramdisk.h" + +#include <string.h> + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/* + * Interface implementation. + */ +static bool overflow(const RamDisk *rd, uint32_t startblk, uint32_t n) { + return (startblk + n) > rd->blk_num; +} + +static bool is_inserted(void *instance) { + (void)instance; + return true; +} + +static bool is_protected(void *instance) { + RamDisk *rd = instance; + if (BLK_READY == rd->state) { + return rd->readonly; + } + else { + return true; + } +} + +static bool connect(void *instance) { + RamDisk *rd = instance; + if (BLK_STOP == rd->state) { + rd->state = BLK_READY; + } + return HAL_SUCCESS; +} + +static bool disconnect(void *instance) { + RamDisk *rd = instance; + if (BLK_STOP != rd->state) { + rd->state = BLK_STOP; + } + return HAL_SUCCESS; +} + +static bool read(void *instance, uint32_t startblk, + uint8_t *buffer, uint32_t n) { + + RamDisk *rd = instance; + + if (overflow(rd, startblk, n)) { + return HAL_FAILED; + } + else { + const uint32_t bs = rd->blk_size; + memcpy(buffer, &rd->storage[startblk * bs], n * bs); + return HAL_SUCCESS; + } +} + +static bool write(void *instance, uint32_t startblk, + const uint8_t *buffer, uint32_t n) { + + RamDisk *rd = instance; + if (overflow(rd, startblk, n)) { + return HAL_FAILED; + } + else { + const uint32_t bs = rd->blk_size; + memcpy(&rd->storage[startblk * bs], buffer, n * bs); + return HAL_SUCCESS; + } +} + +static bool sync(void *instance) { + + RamDisk *rd = instance; + if (BLK_READY != rd->state) { + return HAL_FAILED; + } + else { + return HAL_SUCCESS; + } +} + +static bool get_info(void *instance, BlockDeviceInfo *bdip) { + + RamDisk *rd = instance; + if (BLK_READY != rd->state) { + return HAL_FAILED; + } + else { + bdip->blk_num = rd->blk_num; + bdip->blk_size = rd->blk_size; + return HAL_SUCCESS; + } +} + +/** + * + */ +static const struct BaseBlockDeviceVMT vmt = { + is_inserted, + is_protected, + connect, + disconnect, + read, + write, + sync, + get_info +}; + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief RAM disk object initialization. + * + * @param[in] rdp pointer to @p RamDisk object + * + * @init + */ +void ramdiskObjectInit(RamDisk *rdp) { + + rdp->vmt = &vmt; + rdp->state = BLK_STOP; +} + +/** + * @brief Starts RAM disk. + * + * @param[in] rdp pointer to @p RamDisk object + * @param[in] storage pointer to array representing disk storage + * @param[in] blksize size of blocks in bytes + * @param[in] blknum total number of blocks in device + * @param[in] readonly read only flag + * + * @api + */ +void ramdiskStart(RamDisk *rdp, uint8_t *storage, uint32_t blksize, + uint32_t blknum, bool readonly) { + + osalDbgCheck(rdp != NULL); + + osalSysLock(); + osalDbgAssert((rdp->state == BLK_STOP) || (rdp->state == BLK_READY), + "invalid state"); + rdp->blk_num = blknum; + rdp->blk_size = blksize; + rdp->readonly = readonly; + rdp->storage = storage; + rdp->state = BLK_READY; + osalSysUnlock(); +} + +/** + * @brief Stops RAM disk. + * + * @param[in] rdp pointer to @p RamDisk object + * + * @api + */ +void ramdiskStop(RamDisk *rdp) { + + osalDbgCheck(rdp != NULL); + + osalSysLock(); + osalDbgAssert((rdp->state == BLK_STOP) || (rdp->state == BLK_READY), + "invalid state"); + rdp->storage = NULL; + rdp->state = BLK_STOP; + osalSysUnlock(); +} + +/** @} */ diff --git a/os/various/ramdisk.h b/os/various/ramdisk.h new file mode 100644 index 0000000..0860662 --- /dev/null +++ b/os/various/ramdisk.h @@ -0,0 +1,86 @@ +/* + ChibiOS/HAL - Copyright (C) 2016 Uladzimir Pylinsky aka barthess + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file ramdisk.h + * @brief Virtual block devise driver header. + * + * @addtogroup ramdisk + * @{ + */ + +#ifndef RAMDISK_H_ +#define RAMDISK_H_ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +typedef struct RamDisk RamDisk; + +/** + * + */ +#define _ramdisk_device_data \ + _base_block_device_data \ + uint8_t *storage; \ + uint32_t blk_size; \ + uint32_t blk_num; \ + bool readonly; + +/** + * + */ +struct RamDisk { + /** @brief Virtual Methods Table.*/ + const struct BaseBlockDeviceVMT *vmt; + _ramdisk_device_data +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void ramdiskObjectInit(RamDisk *rdp); + void ramdiskStart(RamDisk *rdp, uint8_t *storage, uint32_t blksize, + uint32_t blknum, bool readonly); + void ramdiskStop(RamDisk *rdp); +#ifdef __cplusplus +} +#endif + +#endif /* RAMDISK_H_ */ + +/** @} */ diff --git a/os/various/tribuf.h b/os/various/tribuf.h index 4ba3f25..8d8f9f4 100644 --- a/os/various/tribuf.h +++ b/os/various/tribuf.h @@ -22,8 +22,8 @@ * @{
*/
-#ifndef _TRIBUF_H_
-#define _TRIBUF_H_
+#ifndef TRIBUF_H_
+#define TRIBUF_H_
/*===========================================================================*/
/* Driver constants. */
@@ -221,5 +221,5 @@ extern "C" { }
#endif
-#endif /* _TRIBUF_H_ */
+#endif /* TRIBUF_H_ */
/** @} */
|