/* Driver for Realtek RTS51xx USB card reader * * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see #include #include #include #include "debug.h" #include "trace.h" #include "rts51x.h" #include "rts51x_transport.h" #include "rts51x_scsi.h" #include "rts51x_card.h" #include "rts51x_chip.h" #include "sd.h" #ifdef SUPPORT_CPRM int reset_sd(struct rts51x_chip *chip); int sd_check_data0_status(struct rts51x_chip *chip); int sd_read_data(struct rts51x_chip *chip, u8 trans_mode, u8 *cmd, int cmd_len, u16 byte_cnt, u16 blk_cnt, u8 bus_width, u8 *buf, int buf_len, int timeout); static inline int get_rsp_type(u8 rsp_code, u8 *rsp_type, int *rsp_len) { if (!rsp_type || !rsp_len) { return STATUS_FAIL; } switch (rsp_code) { case 0x03: *rsp_type = SD_RSP_TYPE_R0; *rsp_len = 0; break; case 0x04: *rsp_type = SD_RSP_TYPE_R1; *rsp_len = 6; break; case 0x05: *rsp_type = SD_RSP_TYPE_R1b; *rsp_len = 6; break; case 0x06: *rsp_type = SD_RSP_TYPE_R2; *rsp_len = 17; break; case 0x07: *rsp_type = SD_RSP_TYPE_R3; *rsp_len = 6; break; default: return STATUS_FAIL; } return STATUS_SUCCESS; } int soft_reset_sd_card(struct rts51x_chip *chip) { return reset_sd(chip); } int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx, u32 arg, u8 rsp_type, u8 *rsp, int rsp_len, int special_check) { int retval; int timeout = 50; u16 reg_addr; u8 buf[17], stat; int len = 2; int rty_cnt = 0; RTS51X_DEBUGP(("EXT SD/MMC CMD %d\n", cmd_idx)); if (rsp_type == SD_RSP_TYPE_R1b) { timeout = 3000; } RTY_SEND_CMD: rts51x_init_cmd(chip); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); rts51x_add_cmd(chip, READ_REG_CMD, SD_STAT1, 0, 0); if (CHECK_USB(chip, USB_20)) { if (rsp_type == SD_RSP_TYPE_R2) { for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr ++) { rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); } len = 19; } else if (rsp_type != SD_RSP_TYPE_R0) { for (reg_addr = SD_CMD0; reg_addr <= SD_CMD4; reg_addr ++) { rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); } len = 8; } else { len = 3; } rts51x_add_cmd(chip, READ_REG_CMD, SD_CMD5, 0, 0); } else { len = 2; } retval = rts51x_send_cmd(chip, MODE_CR, 100); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, retval); } retval = rts51x_get_rsp(chip, len, timeout); #ifdef RCC_BUG_FIX_SP if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1)) { u8 tmpvalue; u16 num = 0; rts51x_ep0_read_register(chip, SFSM_ED, &tmpvalue); if(!(tmpvalue&CARD_ERR)) { for(num=0;num < 1000;num++) { rts51x_ep0_read_register(chip, SD_TRANSFER, &tmpvalue); if(tmpvalue&(SD_TRANSFER_END)) { break; } wait_timeout(1); } if((tmpvalue&SD_TRANSFER_ERR)||(num==1000)) { retval = STATUS_FAIL; } else { if(len == 2) { *chip->rsp_buf=tmpvalue; rts51x_ep0_read_register(chip,SD_STAT1,chip->rsp_buf+1); } else if(len ==19) { *chip->rsp_buf=tmpvalue; rts51x_ep0_read_register(chip,SD_STAT1,chip->rsp_buf+1); for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr ++) { rts51x_ep0_read_register(chip, reg_addr, chip->rsp_buf+reg_addr-PPBUF_BASE2+2); } rts51x_ep0_read_register(chip, SD_CMD5, chip->rsp_buf+18); } else if(len == 8) { *chip->rsp_buf=tmpvalue; rts51x_ep0_read_register(chip,SD_STAT1,chip->rsp_buf+1); for (reg_addr = SD_CMD0; reg_addr <= SD_CMD5; reg_addr ++) { rts51x_ep0_read_register(chip, reg_addr, chip->rsp_buf+reg_addr-SD_CMD0+2); } } else if(len ==3) { *chip->rsp_buf=tmpvalue; rts51x_ep0_read_register(chip,SD_STAT1,chip->rsp_buf+1); rts51x_ep0_read_register(chip, SD_CMD5, chip->rsp_buf+2); } retval = STATUS_SUCCESS; } } rts51x_reset_pipe(chip,0); rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH); rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8); } #endif if (CHECK_SD_TRANS_FAIL(chip, retval)) { rts51x_clear_sd_error(chip); if (retval == STATUS_TIMEDOUT) { if (rsp_type & SD_WAIT_BUSY_END) { retval = sd_check_data0_status(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, retval); } } } TRACE_RET(chip, STATUS_FAIL); } if (rsp_type == SD_RSP_TYPE_R0) { return STATUS_SUCCESS; } if (CHECK_USB(chip, USB_20)) { rts51x_read_rsp_buf(chip, 2, buf, len - 2); } else { if (rsp_type == SD_RSP_TYPE_R2) { reg_addr = PPBUF_BASE2; len = 16; } else { reg_addr = SD_CMD0; len = 5; } #ifdef RCC_BUG_FIX_SP if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1)) { do{ if(rsp_type == SD_RSP_TYPE_R2) { rts51x_ep0_read_register(chip, reg_addr+16-len, buf+16-len); } else { rts51x_ep0_read_register(chip, reg_addr+5-len, buf+5-len); } len--; }while(len>0); } else{ #endif retval = rts51x_seq_read_register(chip, reg_addr, (unsigned short)len, buf); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, retval); } #ifdef RCC_BUG_FIX_SP } #endif RTS51X_READ_REG(chip, SD_CMD5, buf + len); } stat = chip->rsp_buf[1]; if ((buf[0] & 0xC0) != 0) { TRACE_RET(chip, STATUS_FAIL); } if (!(rsp_type & SD_NO_CHECK_CRC7)) { if (stat & SD_CRC7_ERR) { if (cmd_idx == WRITE_MULTIPLE_BLOCK) { TRACE_RET(chip, STATUS_FAIL); } if (rty_cnt < SD_MAX_RETRY_COUNT) { wait_timeout(20); rty_cnt ++; goto RTY_SEND_CMD; } else { TRACE_RET(chip, STATUS_FAIL); } } } if ((cmd_idx == SELECT_CARD) || (cmd_idx == APP_CMD) || (cmd_idx == SEND_STATUS) || (cmd_idx == STOP_TRANSMISSION)) { if ((cmd_idx != STOP_TRANSMISSION) && (special_check == 0)) { if (buf[1] & 0x80) { TRACE_RET(chip, STATUS_FAIL); } } #ifdef SUPPORT_SD_LOCK if (buf[1] & 0x7D) #else if (buf[1] & 0x7F) #endif { TRACE_RET(chip, STATUS_FAIL); } if (buf[2] & 0xF8) { TRACE_RET(chip, STATUS_FAIL); } if (cmd_idx == SELECT_CARD) { if (rsp_type == SD_RSP_TYPE_R2) { if ((buf[3] & 0x1E) != 0x04) { TRACE_RET(chip, STATUS_FAIL); } } else if (rsp_type == SD_RSP_TYPE_R2) { if ((buf[3] & 0x1E) != 0x03) { TRACE_RET(chip, STATUS_FAIL); } } } } if (rsp && rsp_len) { memcpy(rsp, buf, rsp_len); } return STATUS_SUCCESS; } int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type) { int retval, rsp_len; u16 reg_addr; if (rsp_type == SD_RSP_TYPE_R0) { return STATUS_SUCCESS; } rts51x_init_cmd(chip); if (rsp_type == SD_RSP_TYPE_R2) { for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr ++) { rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0); } rsp_len = 17; } else if (rsp_type != SD_RSP_TYPE_R0) { for (reg_addr = SD_CMD0; reg_addr <= SD_CMD4; reg_addr ++) { rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0); } rsp_len = 6; } rts51x_add_cmd(chip, READ_REG_CMD, SD_CMD5, 0xFF, 0); retval = rts51x_send_cmd(chip, MODE_CR, 100); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, retval); } retval = rts51x_get_rsp(chip, rsp_len, 100); #ifdef RCC_BUG_FIX_SP if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1)) { u8 tmpvalue; chip->rcc_read_response = 0; rts51x_ep0_read_register(chip, SFSM_ED, &tmpvalue); if(!(tmpvalue&CARD_ERR)) { if(len ==17) { for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr ++) { rts51x_ep0_read_register(chip, reg_addr, chip->rsp_buf+reg_addr-PPBUF_BASE2); } rts51x_ep0_read_register(chip, SD_CMD5, chip->rsp_buf+16); } else if(len == 6) { for (reg_addr = SD_CMD0; reg_addr <= SD_CMD5; reg_addr ++) { rts51x_ep0_read_register(chip, reg_addr, chip->rsp_buf+reg_addr-SD_CMD0); } } retval = STATUS_SUCCESS; } rts51x_reset_pipe(chip,0); rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH); rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8); } #endif if (retval != STATUS_SUCCESS) { TRACE_RET(chip, retval); } if (rsp) { int min_len = (rsp_len < len) ? rsp_len : len; memcpy(rsp, rts51x_get_rsp_data(chip), min_len); RTS51X_DEBUGP(("min_len = %d\n", min_len)); RTS51X_DEBUGP(("Response in cmd buf: 0x%x 0x%x 0x%x 0x%x\n", rsp[0], rsp[1], rsp[2], rsp[3])); } return STATUS_SUCCESS; } int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun, u8 cmd_idx, u8 standby, u8 acmd, u8 rsp_code, u32 arg) { struct sd_info *sd_card = &(chip->sd_card); int retval, rsp_len; u8 rsp_type; retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); TRACE_RET(chip, TRANSPORT_FAILED); } retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } sd_card->last_rsp_type = rsp_type; retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } #ifdef SUPPORT_SD_LOCK if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { if (CHK_MMC_8BIT(sd_card)) { retval = rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_8); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { retval = rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } } } #else rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4); #endif if (standby) { retval = sd_select_card(chip, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Cmd_Failed); } } if (acmd) { retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Cmd_Failed); } } retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type, sd_card->rsp, rsp_len, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Cmd_Failed); } if (standby) { retval = sd_select_card(chip, 1); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Cmd_Failed); } } #ifdef SUPPORT_SD_LOCK retval = sd_update_lock_status(chip); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Cmd_Failed); } #endif return TRANSPORT_GOOD; SD_Execute_Cmd_Failed: sd_card->pre_cmd_err = 1; set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); release_sd_card(chip); do_reset_sd_card(chip); if (!(chip->card_ready & SD_CARD)) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); } TRACE_RET(chip, TRANSPORT_FAILED); } int ext_sd_execute_read_data(struct rts51x_chip *chip, unsigned int lun, u8 cmd_idx, u8 cmd12, u8 standby, u8 acmd, u8 rsp_code, u32 arg, u32 data_len, void *data_buf, unsigned int buf_len, int use_sg) { struct sd_info *sd_card = &(chip->sd_card); int retval, rsp_len, i; int cmd13_checkbit = 0, read_err = 0; u8 rsp_type, bus_width; if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); TRACE_RET(chip, TRANSPORT_FAILED); } retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, STATUS_FAIL); } retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } sd_card->last_rsp_type = rsp_type; retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } #ifdef SUPPORT_SD_LOCK if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { if (CHK_MMC_8BIT(sd_card)) { bus_width = SD_BUS_WIDTH_8; } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { bus_width = SD_BUS_WIDTH_4; } else { bus_width = SD_BUS_WIDTH_1; } } else { bus_width = SD_BUS_WIDTH_4; } RTS51X_DEBUGP(("bus_width = %d\n", bus_width)); #else bus_width = SD_BUS_WIDTH_4; #endif if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } if (standby) { retval = sd_select_card(chip, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } if (acmd) { retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } if (data_len <= 512) { int min_len; u8 *buf; u16 byte_cnt, blk_cnt; u8 cmd[5]; unsigned int offset = 0; void *sg = NULL; byte_cnt = (u16)(data_len & 0x3FF); blk_cnt = 1; cmd[0] = 0x40 | cmd_idx; cmd[1] = (u8)(arg >> 24); cmd[2] = (u8)(arg >> 16); cmd[3] = (u8)(arg >> 8); cmd[4] = (u8)arg; buf = (u8 *)kmalloc(data_len, GFP_KERNEL); if (buf == NULL) { TRACE_RET(chip, TRANSPORT_ERROR); } retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, byte_cnt, blk_cnt, bus_width, buf, data_len, 2000); if (retval != STATUS_SUCCESS) { read_err = 1; kfree(buf); rts51x_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } min_len = min(data_len, buf_len); if (use_sg) { rts51x_access_sglist(buf, min_len, (void *)data_buf, &sg, &offset, TO_XFER_BUF); } else { memcpy(data_buf, buf, min_len); } kfree(buf); } else if (!(data_len & 0x1FF)) { rts51x_init_cmd(chip); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, (u8)(data_len >> 17)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, (u8)((data_len & 0x0001FE00) >> 9)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03, bus_width); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); trans_dma_enable(DMA_FROM_DEVICE, chip, data_len, DMA_512); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF, SD_TM_AUTO_READ_2 | SD_TRANSFER_START); rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); retval = rts51x_send_cmd(chip, MODE_CDIR, 100); if (retval != STATUS_SUCCESS) { read_err = 1; rts51x_ep0_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } retval = rts51x_transfer_data_rcc(chip, RCV_BULK_PIPE(chip), data_buf, buf_len, use_sg, NULL, 10000, STAGE_DI); if (retval != STATUS_SUCCESS) { read_err = 1; rts51x_ep0_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } #ifdef RCC_BUG_FIX_SP if(chip->rcc_read_response) { u8 tmpvalue; u16 num; chip->rcc_read_response = 0; for(num=0;num < 6000;num++) { rts51x_ep0_read_register(chip, SD_TRANSFER, &tmpvalue); if(tmpvalue&SD_TRANSFER_END) { break; } wait_timeout(1); } if((tmpvalue&SD_TRANSFER_ERR)||(num==6000)) { read_err = 1; rts51x_clear_sd_error(chip); TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } else { retval = rts51x_get_rsp(chip, 1, 600); if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1)) { u8 tmpvalue; u16 num; rts51x_reset_pipe(chip,0); rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH); rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8); for(num=0;num < 600;num++) { rts51x_ep0_read_register(chip, SD_TRANSFER, &tmpvalue); if(tmpvalue&SD_TRANSFER_END) { break; } wait_timeout(1); } if((tmpvalue&SD_TRANSFER_ERR)||(num==600)) { retval = STATUS_FAIL; } else { *chip->rsp_buf = tmpvalue; retval = STATUS_SUCCESS; } } if (CHECK_SD_TRANS_FAIL(chip, retval)) { read_err = 1; rts51x_ep0_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } #else retval = rts51x_get_rsp(chip, 1, 500); if (CHECK_SD_TRANS_FAIL(chip, retval)) { read_err = 1; rts51x_ep0_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } #endif } else { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } retval = ext_sd_get_rsp(chip, rsp_len, sd_card->rsp, rsp_type); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } if (standby) { retval = sd_select_card(chip, 1); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } if (cmd12) { retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, SD_RSP_TYPE_R1b, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } } if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } rts51x_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02); rts51x_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); } if (standby || cmd12) { cmd13_checkbit = 1; } for (i = 0; i < 3; i++) { retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, cmd13_checkbit); if (retval == STATUS_SUCCESS) { break; } } if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); } return TRANSPORT_GOOD; SD_Execute_Read_Cmd_Failed: sd_card->pre_cmd_err = 1; set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); if (read_err) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); } release_sd_card(chip); do_reset_sd_card(chip); if (!(chip->card_ready & SD_CARD)) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); } TRACE_RET(chip, TRANSPORT_FAILED); } int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun, u8 cmd_idx, u8 cmd12, u8 standby, u8 acmd, u8 rsp_code, u32 arg, u32 data_len, void *data_buf, unsigned int buf_len, int use_sg) { struct sd_info *sd_card = &(chip->sd_card); int retval, rsp_len; int cmd13_checkbit = 0, write_err = 0; u8 rsp_type; u32 i; #ifdef SUPPORT_SD_LOCK int lock_cmd_fail = 0; u8 sd_lock_state = 0; u8 lock_cmd_type = 0; #endif if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); TRACE_RET(chip, TRANSPORT_FAILED); } retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, STATUS_FAIL); } #ifdef SUPPORT_SD_LOCK if (cmd_idx == LOCK_UNLOCK) { sd_lock_state = sd_card->sd_lock_status; sd_lock_state &= SD_LOCKED; } #endif retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } sd_card->last_rsp_type = rsp_type; retval = sd_switch_clock(chip); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } #ifdef SUPPORT_SD_LOCK if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { if (CHK_MMC_8BIT(sd_card)) { retval = rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_8); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { retval = rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4); if (retval != STATUS_SUCCESS) { TRACE_RET(chip, TRANSPORT_FAILED); } } } #else rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4); #endif if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } if (standby) { retval = sd_select_card(chip, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } if (acmd) { retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type, sd_card->rsp, rsp_len, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } if (data_len <= 512) { u8 *buf; unsigned int offset = 0; void *sg = NULL; buf = (u8 *)kmalloc(data_len, GFP_KERNEL); if (buf == NULL) { TRACE_RET(chip, TRANSPORT_ERROR); } if (use_sg) { rts51x_access_sglist(buf, data_len, (void *)data_buf, &sg, &offset, FROM_XFER_BUF); } else { memcpy(buf, data_buf, data_len); } #ifdef SUPPORT_SD_LOCK if (cmd_idx == LOCK_UNLOCK) { lock_cmd_type = buf[0] & 0x0F; } #endif if (data_len > 256) { rts51x_init_cmd(chip); for (i = 0; i < 256; i++) { rts51x_add_cmd(chip, WRITE_REG_CMD, (u16)(PPBUF_BASE2 + i), 0xFF, buf[i]); } retval = rts51x_send_cmd(chip, MODE_C, 250); if (retval != STATUS_SUCCESS) { kfree(buf); TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } rts51x_init_cmd(chip); for (i = 256; i < data_len; i++) { rts51x_add_cmd(chip, WRITE_REG_CMD, (u16)(PPBUF_BASE2 + i), 0xFF, buf[i]); } retval = rts51x_send_cmd(chip, MODE_C, 250); if (retval != STATUS_SUCCESS) { kfree(buf); TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } else { rts51x_init_cmd(chip); for (i = 0; i < data_len; i++) { rts51x_add_cmd(chip, WRITE_REG_CMD, (u16)(PPBUF_BASE2 + i), 0xFF, buf[i]); } retval = rts51x_send_cmd(chip, MODE_C, 250); if (retval != STATUS_SUCCESS) { kfree(buf); TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } kfree(buf); rts51x_init_cmd(chip); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, (u8)((data_len >> 8) & 0x03)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)data_len); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x00); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x01); rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF, SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START); rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); retval = rts51x_send_cmd(chip, MODE_CR, 100); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } retval = rts51x_get_rsp(chip, 1, 250); if (CHECK_SD_TRANS_FAIL(chip, retval)) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } else if (!(data_len & 0x1FF)) { rts51x_init_cmd(chip); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, (u8)(data_len >> 17)); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, (u8)((data_len & 0x0001FE00) >> 9)); trans_dma_enable(DMA_TO_DEVICE, chip, data_len, DMA_512); rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF, SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START); rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); retval = rts51x_send_cmd(chip, MODE_CDOR, 100); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } retval = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip), data_buf, buf_len, use_sg, NULL, 10000, STAGE_DO); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } retval = rts51x_get_rsp(chip, 1, 10000); #ifdef RCC_BUG_FIX_SP if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1)) { u8 tmpvalue; int num = 0; chip->rcc_read_response = 0; rts51x_ep0_read_register(chip, SFSM_ED, &tmpvalue); if(!(tmpvalue&CARD_ERR)) { for(num=0;num < 6000;num++) { rts51x_ep0_read_register(chip, SD_TRANSFER, &tmpvalue); if(tmpvalue&SD_TRANSFER_END) { break; } wait_timeout(1); } } if((tmpvalue&SD_TRANSFER_ERR)||(num==6000)) { retval = STATUS_FAIL; } else { *chip->rsp_buf = tmpvalue; retval = STATUS_SUCCESS; } rts51x_reset_pipe(chip,0); rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH); rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8); } #endif if (CHECK_SD_TRANS_FAIL(chip, retval)) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } else { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } if (retval < 0) { write_err = 1; rts51x_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } #ifdef SUPPORT_SD_LOCK if (cmd_idx == LOCK_UNLOCK) { if (lock_cmd_type == SD_ERASE) { sd_card->sd_erase_status = SD_UNDER_ERASING; scsi_set_resid(chip->srb, 0); return TRANSPORT_GOOD; } rts51x_init_cmd(chip); rts51x_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS, SD_DAT0_STATUS); retval = rts51x_send_cmd(chip, MODE_CR, 250); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } rts51x_get_rsp(chip, 1, 200); retval = sd_update_lock_status(chip); if (retval != STATUS_SUCCESS) { RTS51X_DEBUGP(("Lock command fail!\n")); lock_cmd_fail = 1; } } #endif if (standby) { retval = sd_select_card(chip, 1); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } if (cmd12) { retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, SD_RSP_TYPE_R1b, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0, 0); if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } rts51x_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02); rts51x_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); } if (cmd12 || standby) { cmd13_checkbit = 1; } for (i = 0; i < 3; i++) { retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, cmd13_checkbit); if (retval == STATUS_SUCCESS) { break; } } if (retval != STATUS_SUCCESS) { TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } #ifdef SUPPORT_SD_LOCK if (cmd_idx == LOCK_UNLOCK) { if (!lock_cmd_fail) { RTS51X_DEBUGP(("lock_cmd_type = 0x%x\n", lock_cmd_type)); if (lock_cmd_type & SD_CLR_PWD) { sd_card->sd_lock_status &= ~SD_PWD_EXIST; } if (lock_cmd_type & SD_SET_PWD) { sd_card->sd_lock_status |= SD_PWD_EXIST; } } RTS51X_DEBUGP(("sd_lock_state = 0x%x, sd_card->sd_lock_status = 0x%x\n", sd_lock_state, sd_card->sd_lock_status)); if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) { sd_card->sd_lock_notify = 1; if (sd_lock_state) { if (sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) { sd_card->sd_lock_status |= (SD_UNLOCK_POW_ON| SD_SDR_RST); if (CHK_SD(sd_card)) { retval = reset_sd(chip); if (retval != STATUS_SUCCESS) { sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON| SD_SDR_RST); TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); } } sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON| SD_SDR_RST); } } } } if (lock_cmd_fail) { scsi_set_resid(chip->srb, 0); set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); TRACE_RET(chip, TRANSPORT_FAILED); } #endif return TRANSPORT_GOOD; SD_Execute_Write_Cmd_Failed: sd_card->pre_cmd_err = 1; set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); if (write_err) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); } release_sd_card(chip); do_reset_sd_card(chip); if (!(chip->card_ready & SD_CARD)) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); } TRACE_RET(chip, TRANSPORT_FAILED); } int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); unsigned int lun = SCSI_LUN(srb); int len; u8 buf[18] = { 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x53, 0x44, 0x20, 0x43, 0x61, 0x72, 0x64, 0x00, 0x00, 0x00, }; sd_card->pre_cmd_err = 0; if (!(CHK_BIT(chip->lun_mc, lun))) { SET_BIT(chip->lun_mc, lun); set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); TRACE_RET(chip, TRANSPORT_FAILED); } if ((0x53 != srb->cmnd[2]) || (0x44 != srb->cmnd[3]) || (0x20 != srb->cmnd[4]) || (0x43 != srb->cmnd[5]) || (0x61 != srb->cmnd[6]) || (0x72 != srb->cmnd[7]) || (0x64 != srb->cmnd[8])) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } switch (srb->cmnd[1] & 0x0F) { case 0: sd_card->sd_pass_thru_en = 0; break; case 1: sd_card->sd_pass_thru_en = 1; break; default: set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } buf[5] = (1 == CHK_SD(sd_card)) ? 0x01 : 0x02; if (chip->card_wp & SD_CARD) { buf[5] |= 0x80; } buf[6] = (u8)(sd_card->sd_addr >> 16); buf[7] = (u8)(sd_card->sd_addr >> 24); buf[15] = chip->max_lun; len = min(18, (int)scsi_bufflen(srb)); rts51x_set_xfer_buf(buf, len, srb); return TRANSPORT_GOOD; } int sd_execute_no_data(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); unsigned int lun = SCSI_LUN(srb); int retval; u8 cmd_idx, rsp_code; u8 standby = 0, acmd = 0; u32 arg; if (!sd_card->sd_pass_thru_en) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } cmd_idx = srb->cmnd[2] & 0x3F; if (srb->cmnd[1] & 0x02) { standby = 1; } if (srb->cmnd[1] & 0x01) { acmd = 1; } arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | ((u32)srb->cmnd[5] << 8) | srb->cmnd[6]; rsp_code = srb->cmnd[10]; retval = ext_sd_execute_no_data(chip, lun, cmd_idx, standby, acmd, rsp_code, arg); scsi_set_resid(srb, 0); return retval; } int sd_execute_read_data(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); int retval; unsigned int lun = SCSI_LUN(srb); u8 cmd_idx, rsp_code, send_cmd12 = 0, standby = 0, acmd = 0; u32 arg, data_len; if (!sd_card->sd_pass_thru_en) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } cmd_idx = srb->cmnd[2] & 0x3F; if (srb->cmnd[1] & 0x04) { send_cmd12 = 1; } if (srb->cmnd[1] & 0x02) { standby = 1; } if (srb->cmnd[1] & 0x01) { acmd = 1; } arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | ((u32)srb->cmnd[5] << 8) | srb->cmnd[6]; data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] << 8) | srb->cmnd[9]; rsp_code = srb->cmnd[10]; retval = ext_sd_execute_read_data(chip, lun, cmd_idx, send_cmd12, standby, acmd, rsp_code, arg, data_len, scsi_sglist(srb), scsi_bufflen(srb), scsi_sg_count(srb)); scsi_set_resid(srb, 0); return retval; } int sd_execute_write_data(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); int retval; unsigned int lun = SCSI_LUN(srb); u8 cmd_idx, rsp_code, send_cmd12 = 0, standby = 0, acmd = 0; u32 data_len, arg; if (!sd_card->sd_pass_thru_en) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } cmd_idx = srb->cmnd[2] & 0x3F; if (srb->cmnd[1] & 0x04) { send_cmd12 = 1; } if (srb->cmnd[1] & 0x02) { standby = 1; } if (srb->cmnd[1] & 0x01) { acmd = 1; } data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] << 8) | srb->cmnd[9]; arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | ((u32)srb->cmnd[5] << 8) | srb->cmnd[6]; rsp_code = srb->cmnd[10]; retval = ext_sd_execute_write_data(chip, lun, cmd_idx, send_cmd12, standby, acmd, rsp_code, arg, data_len, scsi_sglist(srb), scsi_bufflen(srb), scsi_sg_count(srb)); scsi_set_resid(srb, 0); return retval; } int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); unsigned int lun = SCSI_LUN(srb); int count; u16 data_len; if (!sd_card->sd_pass_thru_en) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); TRACE_RET(chip, TRANSPORT_FAILED); } data_len = ((u16)srb->cmnd[7] << 8) | srb->cmnd[8]; if (sd_card->last_rsp_type == SD_RSP_TYPE_R0) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } else if (sd_card->last_rsp_type == SD_RSP_TYPE_R2) { count = (data_len < 17) ? data_len : 17; } else { count = (data_len < 6) ? data_len : 6; } rts51x_set_xfer_buf(sd_card->rsp, count, srb); RTS51X_DEBUGP(("Response length: %d\n", data_len)); RTS51X_DEBUGP(("Response: 0x%x 0x%x 0x%x 0x%x\n", sd_card->rsp[0], sd_card->rsp[1], sd_card->rsp[2], sd_card->rsp[3])); scsi_set_resid(srb, 0); return TRANSPORT_GOOD; } int sd_hw_rst(struct scsi_cmnd *srb, struct rts51x_chip *chip) { struct sd_info *sd_card = &(chip->sd_card); unsigned int lun = SCSI_LUN(srb); int retval; if (!sd_card->sd_pass_thru_en) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); TRACE_RET(chip, TRANSPORT_FAILED); } if ((0x53 != srb->cmnd[2]) || (0x44 != srb->cmnd[3]) || (0x20 != srb->cmnd[4]) || (0x43 != srb->cmnd[5]) || (0x61 != srb->cmnd[6]) || (0x72 != srb->cmnd[7]) || (0x64 != srb->cmnd[8])) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } switch (srb->cmnd[1] & 0x0F) { case 0: #ifdef SUPPORT_SD_LOCK if (0x64 == srb->cmnd[9]) { sd_card->sd_lock_status |= SD_SDR_RST; } #endif retval = reset_sd_card(chip); if (retval != STATUS_SUCCESS) { #ifdef SUPPORT_SD_LOCK sd_card->sd_lock_status &= ~SD_SDR_RST; #endif set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); sd_card->pre_cmd_err = 1; TRACE_RET(chip, TRANSPORT_FAILED); } #ifdef SUPPORT_SD_LOCK sd_card->sd_lock_status &= ~SD_SDR_RST; #endif break; case 1: retval = soft_reset_sd_card(chip); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); sd_card->pre_cmd_err = 1; TRACE_RET(chip, TRANSPORT_FAILED); } break; default: set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } scsi_set_resid(srb, 0); return TRANSPORT_GOOD; } #endif