/* * Performs a write request for SDHC. */ static int sdhc_write_request(struct sd_host *host, struct request *req) { int i; unsigned long nr_blocks; /* in card blocks */ size_t block_len; /* in bytes */ unsigned long start; void *buf = req->buffer; int retval; /* FIXME?, maybe should use 2^WRITE_BL_LEN blocks */ /* kernel sectors and card write blocks are both 512 bytes long */ start = blk_rq_pos(req); nr_blocks = blk_rq_cur_sectors(req); block_len = 1 << KERNEL_SECTOR_SHIFT; for (i = 0; i < nr_blocks; i++) { retval = sd_write_single_block(host, start, buf, block_len); if (retval < 0) break; start ++; buf += block_len; } /* number of kernel sectors transferred */ retval = i; return retval; }
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { DRESULT result; if (pdrv >= N_PDRV) { result = RES_ERROR; } else if (!pdrv_data[pdrv].initialized) { result = RES_NOTRDY; } else if (!pdrv_data[pdrv].present) { result = RES_ERROR; } else if (pdrv_data[pdrv].write_protected) { result = RES_ERROR; } else { while (count > 0) { uint32_t addr; int write_res; addr = get_addr(sector, pdrv_data[pdrv].byte_addressable); write_res = sd_write_single_block(addr, buff); if (write_res != 0) { break; } buff += SD_SECTOR_SIZE; sector++; count--; } if (count > 0) { result = RES_ERROR; } else { result = RES_OK; } } return result; }
scsi_cmdret_t scsi_sd_write10( SCSI_PARAMS ) { const sdio_t *sdio = (const sdio_t*)scsi_lun[lun].info; scsi_cdb10_t *cdb10 = (scsi_cdb10_t *)cmd; //uint8_t DPO = (cdb10->cdb_info >> 4) & 0x1; //uint8_t FUA = (cdb10->cdb_info >> 3) & 0x1; uint32_t lba = msbtohost32(cdb10->lba); uint32_t nblocks = msbtohost16(cdb10->length); uint32_t sdsize = sd_get_size(*sdio); sd_card_type_t sdtype = sd_get_type(*sdio); sd_error_t sdret; scsi_cmdret_t ret; uint32_t la = (sdtype != SDHC) ? lba * BLOCKSIZE : lba; sdret = SD_NO_ERROR; sd_transfer_ended = false; sd_set_transfer_handler(*sdio, sd_transfer_handler); if ((lba + nblocks - 1) >= sdsize) { log_error("SCSI Write(10), write beyond limit (limit 0x%08x, request 0x%08x / +%d)",sdsize,lba,nblocks); *status = SCSI_CHECK_CONDITION; return SCSI_CMD_DONE; } if (datamax < BLOCKSIZE) { log_error("SCSI Write(10), write buffer is smaller than a single sector (%d/%d bytes)",datamax,BLOCKSIZE); *status = SCSI_CHECK_CONDITION; return SCSI_CMD_ERROR; } if (cont == 0) { log_info("SCSI Write(10) type %d, lba 0x%08x, length %d",sdtype,lba,nblocks); *status = SCSI_GOOD; return SCSI_CMD_PARTIAL; } else { DBG("-%d-\n",cont); #define TEST_WRITE 0 #if TEST_WRITE == 1 scsi_dump_blk(lba, data, datamax); sdret = SD_NO_ERROR; sd_transfer_ended = true; #else sdret = sd_write_single_block(*sdio, la, data); #endif } if (sdret != SD_NO_ERROR) { log_error("SCSI Write Command Error on SD %d",sdret); *status = SCSI_CHECK_CONDITION; return SCSI_CMD_DONE; } while (!sd_transfer_ended) { ; } sdret = sd_get_status(*sdio); if (sdret != SD_NO_ERROR) { log_error("SCSI Write Error on SD (lba 0x%08x) ret %d",lba,sdret); *status = SCSI_CHECK_CONDITION; return SCSI_CMD_DONE; } switch (nblocks) { case 0: *status = SCSI_CHECK_CONDITION; ret = SCSI_CMD_ERROR; break; case 1: *datalen = BLOCKSIZE; *status = SCSI_GOOD; ret = SCSI_CMD_DONE; break; default: cdb10->lba = msbtohost32( lba + 1 ); cdb10->length = msbtohost16( nblocks - 1 ); *datalen = BLOCKSIZE; *status = SCSI_GOOD; ret = SCSI_CMD_PARTIAL; break; } return ret; }