summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_scsi.c')
-rw-r--r--target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_scsi.c1794
1 files changed, 1794 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_scsi.c b/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_scsi.c
new file mode 100644
index 000000000..0e7e1204a
--- /dev/null
+++ b/target/linux/realtek/files/drivers/usb/misc/rts51xx/rts51x_scsi.c
@@ -0,0 +1,1794 @@
+/* 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 <http:
+ *
+ * Author:
+ * wwang (wei_wang@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+//#include <linux/vmalloc.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+
+#include "debug.h"
+#include "rts51x.h"
+#include "rts51x_chip.h"
+#include "rts51x_scsi.h"
+#include "rts51x_card.h"
+#include "rts51x_transport.h"
+#include "rts51x_sys.h"
+#include "sd_cprm.h"
+#include "ms_mg.h"
+#include "trace.h"
+
+void scsi_show_command(struct scsi_cmnd *srb)
+{
+ char *what = NULL;
+ int i, unknown_cmd = 0;
+
+ switch (srb->cmnd[0]) {
+ case TEST_UNIT_READY: what = (char *)"TEST_UNIT_READY"; break;
+ case REZERO_UNIT: what = (char *)"REZERO_UNIT"; break;
+ case REQUEST_SENSE: what = (char *)"REQUEST_SENSE"; break;
+ case FORMAT_UNIT: what = (char *)"FORMAT_UNIT"; break;
+ case READ_BLOCK_LIMITS: what = (char *)"READ_BLOCK_LIMITS"; break;
+ case 0x07: what = (char *)"REASSIGN_BLOCKS"; break;
+ case READ_6: what = (char *)"READ_6"; break;
+ case WRITE_6: what = (char *)"WRITE_6"; break;
+ case SEEK_6: what = (char *)"SEEK_6"; break;
+ case READ_REVERSE: what = (char *)"READ_REVERSE"; break;
+ case WRITE_FILEMARKS: what = (char *)"WRITE_FILEMARKS"; break;
+ case SPACE: what = (char *)"SPACE"; break;
+ case INQUIRY: what = (char *)"INQUIRY"; break;
+ case RECOVER_BUFFERED_DATA: what = (char *)"RECOVER_BUFFERED_DATA"; break;
+ case MODE_SELECT: what = (char *)"MODE_SELECT"; break;
+ case RESERVE: what = (char *)"RESERVE"; break;
+ case RELEASE: what = (char *)"RELEASE"; break;
+ case COPY: what = (char *)"COPY"; break;
+ case ERASE: what = (char *)"ERASE"; break;
+ case MODE_SENSE: what = (char *)"MODE_SENSE"; break;
+ case START_STOP: what = (char *)"START_STOP"; break;
+ case RECEIVE_DIAGNOSTIC: what = (char *)"RECEIVE_DIAGNOSTIC"; break;
+ case SEND_DIAGNOSTIC: what = (char *)"SEND_DIAGNOSTIC"; break;
+ case ALLOW_MEDIUM_REMOVAL: what = (char *)"ALLOW_MEDIUM_REMOVAL"; break;
+ case SET_WINDOW: what = (char *)"SET_WINDOW"; break;
+ case READ_CAPACITY: what = (char *)"READ_CAPACITY"; break;
+ case READ_10: what = (char *)"READ_10"; break;
+ case WRITE_10: what = (char *)"WRITE_10"; break;
+ case SEEK_10: what = (char *)"SEEK_10"; break;
+ case WRITE_VERIFY: what = (char *)"WRITE_VERIFY"; break;
+ case VERIFY: what = (char *)"VERIFY"; break;
+ case SEARCH_HIGH: what = (char *)"SEARCH_HIGH"; break;
+ case SEARCH_EQUAL: what = (char *)"SEARCH_EQUAL"; break;
+ case SEARCH_LOW: what = (char *)"SEARCH_LOW"; break;
+ case SET_LIMITS: what = (char *)"SET_LIMITS"; break;
+ case READ_POSITION: what = (char *)"READ_POSITION"; break;
+ case SYNCHRONIZE_CACHE: what = (char *)"SYNCHRONIZE_CACHE"; break;
+ case LOCK_UNLOCK_CACHE: what = (char *)"LOCK_UNLOCK_CACHE"; break;
+ case READ_DEFECT_DATA: what = (char *)"READ_DEFECT_DATA"; break;
+ case MEDIUM_SCAN: what = (char *)"MEDIUM_SCAN"; break;
+ case COMPARE: what = (char *)"COMPARE"; break;
+ case COPY_VERIFY: what = (char *)"COPY_VERIFY"; break;
+ case WRITE_BUFFER: what = (char *)"WRITE_BUFFER"; break;
+ case READ_BUFFER: what = (char *)"READ_BUFFER"; break;
+ case UPDATE_BLOCK: what = (char *)"UPDATE_BLOCK"; break;
+ case READ_LONG: what = (char *)"READ_LONG"; break;
+ case WRITE_LONG: what = (char *)"WRITE_LONG"; break;
+ case CHANGE_DEFINITION: what = (char *)"CHANGE_DEFINITION"; break;
+ case WRITE_SAME: what = (char *)"WRITE_SAME"; break;
+ case GPCMD_READ_SUBCHANNEL: what = (char *)"READ SUBCHANNEL"; break;
+ case READ_TOC: what = (char *)"READ_TOC"; break;
+ case GPCMD_READ_HEADER: what = (char *)"READ HEADER"; break;
+ case GPCMD_PLAY_AUDIO_10: what = (char *)"PLAY AUDIO (10)"; break;
+ case GPCMD_PLAY_AUDIO_MSF: what = (char *)"PLAY AUDIO MSF"; break;
+ case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+ what = (char *)"GET EVENT/STATUS NOTIFICATION"; break;
+ case GPCMD_PAUSE_RESUME: what = (char *)"PAUSE/RESUME"; break;
+ case LOG_SELECT: what = (char *)"LOG_SELECT"; break;
+ case LOG_SENSE: what = (char *)"LOG_SENSE"; break;
+ case GPCMD_STOP_PLAY_SCAN: what = (char *)"STOP PLAY/SCAN"; break;
+ case GPCMD_READ_DISC_INFO: what = (char *)"READ DISC INFORMATION"; break;
+ case GPCMD_READ_TRACK_RZONE_INFO:
+ what = (char *)"READ TRACK INFORMATION"; break;
+ case GPCMD_RESERVE_RZONE_TRACK: what = (char *)"RESERVE TRACK"; break;
+ case GPCMD_SEND_OPC: what = (char *)"SEND OPC"; break;
+ case MODE_SELECT_10: what = (char *)"MODE_SELECT_10"; break;
+ case GPCMD_REPAIR_RZONE_TRACK: what = (char *)"REPAIR TRACK"; break;
+ case 0x59: what = (char *)"READ MASTER CUE"; break;
+ case MODE_SENSE_10: what = (char *)"MODE_SENSE_10"; break;
+ case GPCMD_CLOSE_TRACK: what = (char *)"CLOSE TRACK/SESSION"; break;
+ case 0x5C: what = (char *)"READ BUFFER CAPACITY"; break;
+ case 0x5D: what = (char *)"SEND CUE SHEET"; break;
+ case GPCMD_BLANK: what = (char *)"BLANK"; break;
+ case REPORT_LUNS: what = (char *)"REPORT LUNS"; break;
+ case MOVE_MEDIUM: what = (char *)"MOVE_MEDIUM or PLAY AUDIO (12)"; break;
+ case READ_12: what = (char *)"READ_12"; break;
+ case WRITE_12: what = (char *)"WRITE_12"; break;
+ case WRITE_VERIFY_12: what = (char *)"WRITE_VERIFY_12"; break;
+ case SEARCH_HIGH_12: what = (char *)"SEARCH_HIGH_12"; break;
+ case SEARCH_EQUAL_12: what = (char *)"SEARCH_EQUAL_12"; break;
+ case SEARCH_LOW_12: what = (char *)"SEARCH_LOW_12"; break;
+ case SEND_VOLUME_TAG: what = (char *)"SEND_VOLUME_TAG"; break;
+ case READ_ELEMENT_STATUS: what = (char *)"READ_ELEMENT_STATUS"; break;
+ case GPCMD_READ_CD_MSF: what = (char *)"READ CD MSF"; break;
+ case GPCMD_SCAN: what = (char *)"SCAN"; break;
+ case GPCMD_SET_SPEED: what = (char *)"SET CD SPEED"; break;
+ case GPCMD_MECHANISM_STATUS: what = (char *)"MECHANISM STATUS"; break;
+ case GPCMD_READ_CD: what = (char *)"READ CD"; break;
+ case 0xE1: what = (char *)"WRITE CONTINUE"; break;
+ case WRITE_LONG_2: what = (char *)"WRITE_LONG_2"; break;
+ case VENDOR_CMND: what = (char *)"Realtek's vendor command"; break;
+ default: what = (char *)"(unknown command)"; unknown_cmd = 1; break;
+ }
+
+ if (srb->cmnd[0] != TEST_UNIT_READY) {
+ RTS51X_DEBUGP(("Command %s (%d bytes)\n", what, srb->cmd_len));
+ }
+ if (unknown_cmd) {
+ RTS51X_DEBUGP((""));
+ for (i = 0; i < srb->cmd_len && i < 16; i++)
+ RTS51X_DEBUGPN((" %02x", srb->cmnd[i]));
+ RTS51X_DEBUGPN(("\n"));
+ }
+}
+
+void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type)
+{
+ switch (sense_type) {
+ case SENSE_TYPE_MEDIA_CHANGE:
+ set_sense_data(chip, lun, CUR_ERR, 0x06, 0, 0x28, 0, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_NOT_PRESENT:
+ set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x3A, 0, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_LBA_OVER_RANGE:
+ set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x21, 0, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT:
+ set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x25, 0, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_WRITE_PROTECT:
+ set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x27, 0, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR:
+ set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x11, 0, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_WRITE_ERR:
+ set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x0C, 0x02, 0, 0);
+ break;
+
+ case SENSE_TYPE_MEDIA_INVALID_CMD_FIELD:
+ set_sense_data(chip, lun, CUR_ERR, ILGAL_REQ, 0,
+ ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1);
+ break;
+
+ case SENSE_TYPE_FORMAT_IN_PROGRESS:
+ set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0);
+ break;
+
+ case SENSE_TYPE_FORMAT_CMD_FAILED:
+ set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0);
+ break;
+
+#ifdef SUPPORT_MAGIC_GATE
+ case SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB:
+ set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x6F, 0x02, 0, 0);
+ break;
+
+ case SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN:
+ set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x6F, 0x00, 0, 0);
+ break;
+
+ case SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM:
+ set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x30, 0x00, 0, 0);
+ break;
+
+ case SENSE_TYPE_MG_WRITE_ERR:
+ set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x0C, 0x00, 0, 0);
+ break;
+#endif
+
+#ifdef SUPPORT_SD_LOCK
+ case SENSE_TYPE_MEDIA_READ_FORBIDDEN:
+ set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0);
+ break;
+#endif
+
+ case SENSE_TYPE_NO_SENSE:
+ default:
+ set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0);
+ break;
+ }
+}
+
+void set_sense_data(struct rts51x_chip *chip, unsigned int lun, u8 err_code, u8 sense_key,
+ u32 info, u8 asc, u8 ascq, u8 sns_key_info0, u16 sns_key_info1)
+{
+ struct sense_data_t *sense = &(chip->sense_buffer[lun]);
+
+ sense->err_code = err_code;
+ sense->sense_key = sense_key;
+ sense->info[0] = (u8)(info >> 24);
+ sense->info[1] = (u8)(info >> 16);
+ sense->info[2] = (u8)(info >> 8);
+ sense->info[3] = (u8)info;
+
+ sense->ad_sense_len = sizeof(struct sense_data_t) - 8;
+ sense->asc = asc;
+ sense->ascq = ascq;
+ if ( sns_key_info0 != 0 ) {
+ sense->sns_key_info[0] = SKSV | sns_key_info0;
+ sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 8;
+ sense->sns_key_info[2] = sns_key_info1 & 0x0f;
+ }
+}
+
+static int test_unit_ready(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+
+ rts51x_init_cards(chip);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ return TRANSPORT_FAILED;
+ }
+
+ if (!check_lun_mc(chip, lun)) {
+ set_lun_mc(chip, lun);
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
+ return TRANSPORT_FAILED;
+ }
+
+#ifdef SUPPORT_SD_LOCK
+ if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) {
+ struct sd_info *sd_card = &(chip->sd_card);
+ if (sd_card->sd_lock_notify) {
+ sd_card->sd_lock_notify = 0;
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
+ return TRANSPORT_FAILED;
+ } else if (sd_card->sd_lock_status & SD_LOCKED) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
+ return TRANSPORT_FAILED;
+ }
+ }
+#endif
+
+ return TRANSPORT_GOOD;
+}
+
+unsigned char formatter_inquiry_str[20] =
+{
+ 'M','E','M','O','R','Y','S','T','I','C','K',
+ '-', 'M', 'G',
+ 0x0B,
+ 0x00,
+ 0x00,
+ 0x20, 0x20, 0x20,
+};
+
+static int inquiry(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ char *inquiry_default = (char *)"Generic-xD/SD/M.S. 1.00 ";
+ char *inquiry_string;
+ unsigned char sendbytes;
+ unsigned char *buf;
+ u8 card = get_lun_card(chip, lun);
+ int pro_formatter_flag = 0;
+ unsigned char inquiry_buf[] =
+ {
+ QULIFIRE|DRCT_ACCESS_DEV,
+ RMB_DISC|0x0D,
+ 0x00,
+ 0x01,
+ 0x1f,
+ 0x02,
+ 0,
+ REL_ADR|WBUS_32|WBUS_16|SYNC|LINKED|CMD_QUE|SFT_RE,
+ };
+
+ inquiry_string = inquiry_default;
+
+ buf = vmalloc(scsi_bufflen(srb));
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ if (MS_FORMATTER_ENABLED(chip) &&
+ (get_lun2card(chip, lun) & MS_CARD)) {
+ if (!card || (card == MS_CARD)) {
+ pro_formatter_flag = 1;
+ }
+ }
+
+ if (pro_formatter_flag) {
+ if (scsi_bufflen(srb) < 56) {
+ sendbytes = (unsigned char)(scsi_bufflen(srb));
+ } else {
+ sendbytes = 56;
+ }
+ } else {
+ if (scsi_bufflen(srb) < 36) {
+ sendbytes = (unsigned char)(scsi_bufflen(srb));
+ } else {
+ sendbytes = 36;
+ }
+ }
+
+ if (sendbytes > 8) {
+ memcpy(buf, inquiry_buf, 8);
+ memcpy(buf + 8, inquiry_string, sendbytes - 8);
+ if (pro_formatter_flag) {
+ buf[4] = 0x33;
+ }
+ } else {
+ memcpy(buf, inquiry_buf, sendbytes);
+ }
+
+ if (pro_formatter_flag) {
+ if (sendbytes > 36) {
+ memcpy(buf + 36, formatter_inquiry_str, sendbytes - 36);
+ }
+ }
+
+ scsi_set_resid(srb, 0);
+
+ rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
+ vfree(buf);
+
+ return TRANSPORT_GOOD;
+}
+
+
+static int start_stop_unit(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+
+ scsi_set_resid(srb, scsi_bufflen(srb));
+
+ if (srb->cmnd[1] == 1) {
+ return TRANSPORT_GOOD;
+ }
+
+ switch (srb->cmnd[0x4]) {
+ case STOP_MEDIUM:
+ return TRANSPORT_GOOD;
+
+ case UNLOAD_MEDIUM:
+ if (check_card_ready(chip, lun)) {
+ eject_card(chip, lun);
+ }
+ return TRANSPORT_GOOD;
+
+ case MAKE_MEDIUM_READY:
+ case LOAD_MEDIUM:
+ if (check_card_ready(chip, lun)) {
+ return TRANSPORT_GOOD;
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ break;
+ }
+
+ TRACE_RET(chip, TRANSPORT_ERROR);
+}
+
+static int allow_medium_removal(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int prevent;
+
+ prevent = srb->cmnd[4] & 0x1;
+
+ scsi_set_resid(srb, 0);
+
+ if (prevent) {
+ set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ return TRANSPORT_GOOD;
+}
+
+static void ms_mode_sense(struct rts51x_chip *chip, u8 cmd,
+ int lun, u8 *buf, int buf_len)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int sys_info_offset;
+ int data_size = buf_len;
+ int support_format = 0;
+ int i = 0;
+
+ if (cmd == MODE_SENSE) {
+ sys_info_offset = 8;
+ if (data_size > 0x68) {
+ data_size = 0x68;
+ }
+ buf[i++] = 0x67;
+ } else {
+ sys_info_offset = 12;
+ if (data_size > 0x6C) {
+ data_size = 0x6C;
+ }
+ buf[i++] = 0x00;
+ buf[i++] = 0x6A;
+ }
+
+ if (check_card_ready(chip, lun)) {
+ if (CHK_MSXC(ms_card)) {
+ support_format = 1;
+ buf[i++] = 0x40;
+ } else if (CHK_MSPRO(ms_card)) {
+ support_format = 1;
+ buf[i++] = 0x20;
+ } else {
+ buf[i++] = 0x10;
+ }
+
+ if (check_card_wp(chip, lun)) {
+ buf[i++] = 0x80;
+ } else {
+ buf[i++] = 0x00;
+ }
+ } else {
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ }
+
+ buf[i++] = 0x00;
+
+ if (cmd == MODE_SENSE_10) {
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+
+ if (data_size >= 9) {
+ buf[i++] = 0x20;
+ }
+ if (data_size >= 10) {
+ buf[i++] = 0x62;
+ }
+ if (data_size >= 11) {
+ buf[i++] = 0x00;
+ }
+ if (data_size >= 12) {
+ if (support_format) {
+ buf[i++] = 0xC0;
+ } else {
+ buf[i++] = 0x00;
+ }
+ }
+ } else {
+ if (data_size >= 5) {
+ buf[i++] = 0x20;
+ }
+ if (data_size >= 6) {
+ buf[i++] = 0x62;
+ }
+ if (data_size >= 7) {
+ buf[i++] = 0x00;
+ }
+ if (data_size >= 8) {
+ if (support_format) {
+ buf[i++] = 0xC0;
+ } else {
+ buf[i++] = 0x00;
+ }
+ }
+ }
+
+ if (data_size > sys_info_offset) {
+ int len = data_size - sys_info_offset;
+ len = (len < 96) ? len : 96;
+
+ memcpy(buf + sys_info_offset, ms_card->raw_sys_info, len);
+ }
+}
+
+static int mode_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ unsigned int dataSize;
+ int status;
+ int pro_formatter_flag;
+ unsigned char pageCode, *buf;
+ u8 card = get_lun_card(chip, lun);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ scsi_set_resid(srb, scsi_bufflen(srb));
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ pro_formatter_flag = 0;
+ dataSize = 8;
+ if ((get_lun2card(chip, lun) & MS_CARD)) {
+ if (!card || (card == MS_CARD)) {
+ dataSize = 108;
+ if (chip->option.mspro_formatter_enable) {
+ pro_formatter_flag = 1;
+ }
+ }
+ }
+
+ buf = kmalloc(dataSize, GFP_KERNEL);
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ pageCode = srb->cmnd[2] & 0x3f;
+
+ if ((pageCode == 0x3F) || (pageCode == 0x1C) ||
+ (pageCode == 0x00) ||
+ (pro_formatter_flag && (pageCode == 0x20))) {
+ if (srb->cmnd[0] == MODE_SENSE) {
+ if ((pageCode == 0x3F) || (pageCode == 0x20)) {
+ ms_mode_sense(chip, srb->cmnd[0], lun, buf, dataSize);
+ } else {
+ dataSize = 4;
+ buf[0] = 0x03;
+ buf[1] = 0x00;
+ if (check_card_wp(chip, lun)) {
+ buf[2] = 0x80;
+ } else {
+ buf[2] = 0x00;
+ }
+ buf[3] = 0x00;
+ }
+ } else {
+ if ((pageCode == 0x3F) || (pageCode == 0x20)) {
+ ms_mode_sense(chip, srb->cmnd[0], lun, buf, dataSize);
+ } else {
+ dataSize = 8;
+ buf[0] = 0x00;
+ buf[1] = 0x06;
+ buf[2] = 0x00;
+ if (check_card_wp(chip, lun)) {
+ buf[3] = 0x80;
+ } else {
+ buf[3] = 0x00;
+ }
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+ buf[6] = 0x00;
+ buf[7] = 0x00;
+ }
+ }
+ status = TRANSPORT_GOOD;
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ scsi_set_resid(srb, scsi_bufflen(srb));
+ status = TRANSPORT_FAILED;
+ }
+
+ if (status == TRANSPORT_GOOD) {
+ unsigned int len = min(scsi_bufflen(srb), dataSize);
+ rts51x_set_xfer_buf(buf, len, srb);
+ scsi_set_resid(srb, scsi_bufflen(srb) - len);
+ }
+ kfree(buf);
+
+ return status;
+}
+
+static int request_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct sense_data_t *sense;
+ unsigned int lun = SCSI_LUN(srb);
+ struct ms_info *ms_card = &(chip->ms_card);
+ unsigned char *tmp, *buf;
+
+ sense = &(chip->sense_buffer[lun]);
+
+ if ((get_lun_card(chip, lun) == MS_CARD) && PRO_UNDER_FORMATTING(ms_card)) {
+ mspro_format_sense(chip, lun);
+ }
+
+ buf = vmalloc(scsi_bufflen(srb));
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ tmp = (unsigned char *)sense;
+ memcpy(buf, tmp, scsi_bufflen(srb));
+
+ rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
+ vfree(buf);
+
+ scsi_set_resid(srb,0);
+ set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
+ return TRANSPORT_GOOD;
+}
+
+static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+#ifdef SUPPORT_SD_LOCK
+ struct sd_info *sd_card = &(chip->sd_card);
+#endif
+ unsigned int lun = SCSI_LUN(srb);
+ int retval;
+ u32 start_sec;
+ u16 sec_cnt;
+
+ if (!check_card_ready(chip, lun) || (chip->capacity[lun] == 0)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (!check_lun_mc(chip, lun)) {
+ set_lun_mc(chip, lun);
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
+ return TRANSPORT_FAILED;
+ }
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+#ifdef SUPPORT_SD_LOCK
+ if (sd_card->sd_erase_status) {
+ RTS51X_DEBUGP(("SD card being erased!\n"));
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (get_lun_card(chip, lun) == SD_CARD) {
+ if (sd_card->sd_lock_status & SD_LOCKED) {
+ RTS51X_DEBUGP(("SD card locked!\n"));
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+#endif
+
+ if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) {
+ start_sec = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) |
+ ((u32)srb->cmnd[4] << 8) | ((u32)srb->cmnd[5]);
+ sec_cnt = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
+ } else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) {
+ start_sec = ((u32)(srb->cmnd[1] & 0x1F) << 16) |
+ ((u32)srb->cmnd[2] << 8) | ((u32)srb->cmnd[3]);
+ sec_cnt = srb->cmnd[4];
+ } else if ((srb->cmnd[0] == VENDOR_CMND) && (srb->cmnd[1] == SCSI_APP_CMD) &&
+ ((srb->cmnd[2] == PP_READ10) || (srb->cmnd[2] == PP_WRITE10))) {
+ start_sec = ((u32)srb->cmnd[4] << 24) | ((u32)srb->cmnd[5] << 16) |
+ ((u32)srb->cmnd[6] << 8) | ((u32)srb->cmnd[7]);
+ sec_cnt = ((u16)(srb->cmnd[9]) << 8) | srb->cmnd[10];
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if ((start_sec > chip->capacity[lun]) ||
+ ((start_sec + sec_cnt) > chip->capacity[lun])) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LBA_OVER_RANGE);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (sec_cnt == 0) {
+ scsi_set_resid(srb, 0);
+ return TRANSPORT_GOOD;
+ }
+
+ if ((srb->sc_data_direction == DMA_TO_DEVICE) && check_card_wp(chip, lun)) {
+ RTS51X_DEBUGP(("Write protected card!\n"));
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ retval = card_rw(srb, chip, start_sec, sec_cnt);
+ if (retval != STATUS_SUCCESS) {
+ if (srb->sc_data_direction == DMA_FROM_DEVICE) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
+ }
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ scsi_set_resid(srb, 0);
+
+ return TRANSPORT_GOOD;
+}
+
+static int read_format_capacity(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned char *buf;
+ unsigned int lun = SCSI_LUN(srb);
+ unsigned int buf_len;
+ u8 card = get_lun_card(chip, lun);
+ int desc_cnt;
+ int i = 0;
+
+ if (!check_card_ready(chip, lun)) {
+ if (!chip->option.mspro_formatter_enable) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+
+
+ buf_len = (scsi_bufflen(srb) > 12) ? 0x14 : 12;
+
+ buf = kmalloc(buf_len, GFP_KERNEL);
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ buf[i++] = 0;
+ buf[i++] = 0;
+ buf[i++] = 0;
+
+ if ((buf_len > 12) && chip->option.mspro_formatter_enable &&
+ (chip->lun2card[lun] & MS_CARD) &&
+ (!card || (card == MS_CARD))) {
+ buf[i++] = 0x10;
+ desc_cnt = 2;
+ } else {
+ buf[i++] = 0x08;
+ desc_cnt = 1;
+ }
+
+ while (desc_cnt) {
+ if (check_card_ready(chip, lun)) {
+ buf[i++] = (unsigned char)((chip->capacity[lun]) >> 24);
+ buf[i++] = (unsigned char)((chip->capacity[lun]) >> 16);
+ buf[i++] = (unsigned char)((chip->capacity[lun]) >> 8);
+ buf[i++] = (unsigned char)(chip->capacity[lun]);
+
+ if (desc_cnt == 2) {
+ buf[i++] = 2;
+ } else {
+ buf[i++] = 0;
+ }
+ } else {
+ buf[i++] = 0xFF;
+ buf[i++] = 0xFF;
+ buf[i++] = 0xFF;
+ buf[i++] = 0xFF;
+
+ if (desc_cnt == 2) {
+ buf[i++] = 3;
+ } else {
+ buf[i++] = 0;
+ }
+ }
+
+ buf[i++] = 0x00;
+ buf[i++] = 0x02;
+ buf[i++] = 0x00;
+
+ desc_cnt --;
+ }
+
+ buf_len = min(scsi_bufflen(srb), buf_len);
+ rts51x_set_xfer_buf(buf, buf_len, srb);
+ kfree(buf);
+
+ scsi_set_resid(srb, scsi_bufflen(srb) - buf_len);
+
+ return TRANSPORT_GOOD;
+}
+
+static int read_capacity(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned char *buf;
+ unsigned int lun = SCSI_LUN(srb);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (!check_lun_mc(chip, lun)) {
+ set_lun_mc(chip, lun);
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
+ return TRANSPORT_FAILED;
+ }
+
+ buf = kmalloc(8, GFP_KERNEL);
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ buf[0] = (unsigned char)((chip->capacity[lun] - 1) >> 24);
+ buf[1] = (unsigned char)((chip->capacity[lun] - 1) >> 16);
+ buf[2] = (unsigned char)((chip->capacity[lun] - 1) >> 8);
+ buf[3] = (unsigned char)(chip->capacity[lun] - 1);
+
+ buf[4] = 0x00;
+ buf[5] = 0x00;
+ buf[6] = 0x02;
+ buf[7] = 0x00;
+
+ rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
+ kfree(buf);
+
+ scsi_set_resid(srb, 0);
+
+ return TRANSPORT_GOOD;
+}
+
+static int get_dev_status(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ unsigned int buf_len;
+ u8 status[32] = {0};
+
+ rts51x_pp_status(chip, lun, status, 32);
+
+ buf_len = min(scsi_bufflen(srb), (unsigned int)sizeof(status));
+ rts51x_set_xfer_buf(status, buf_len, srb);
+ scsi_set_resid(srb, scsi_bufflen(srb) - buf_len);
+
+ return TRANSPORT_GOOD;
+}
+
+static int read_status(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ u8 rts51x_status[16];
+ unsigned int buf_len;
+ unsigned int lun = SCSI_LUN(srb);
+
+ rts51x_read_status(chip, lun, rts51x_status, 16);
+
+ buf_len = min(scsi_bufflen(srb), (unsigned int)sizeof(rts51x_status));
+ rts51x_set_xfer_buf(rts51x_status, buf_len, srb);
+ scsi_set_resid(srb, scsi_bufflen(srb) - buf_len);
+
+ return TRANSPORT_GOOD;
+}
+
+static int read_mem(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ unsigned short addr, len, i;
+ int retval;
+ u8 *buf;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ addr = ((u16)srb->cmnd[2] << 8) | srb->cmnd[3];
+ len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5];
+
+ if (addr < 0xe000) {
+ RTS51X_DEBUGP(("filter!addr=0x%x\n",addr));
+ return TRANSPORT_GOOD;
+ }
+
+ buf = (u8 *)vmalloc(len);
+ if (!buf) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ for (i = 0; i < len; i++) {
+ retval = rts51x_ep0_read_register(chip, addr + i, buf + i);
+ if (retval != STATUS_SUCCESS) {
+ vfree(buf);
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+
+ len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
+ rts51x_set_xfer_buf(buf, len, srb);
+ scsi_set_resid(srb, scsi_bufflen(srb) - len);
+
+ vfree(buf);
+
+ return TRANSPORT_GOOD;
+}
+
+static int write_mem(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ unsigned short addr, len, i;
+ int retval;
+ u8 *buf;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ addr = ((u16)srb->cmnd[2] << 8) | srb->cmnd[3];
+ len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5];
+
+ if (addr < 0xe000) {
+ RTS51X_DEBUGP(("filter!addr=0x%x\n",addr));
+ return TRANSPORT_GOOD;
+ }
+
+ len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
+ buf = (u8 *)vmalloc(len);
+ if (!buf) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ rts51x_get_xfer_buf(buf, len, srb);
+
+ for (i = 0; i < len; i++) {
+ retval = rts51x_ep0_write_register(chip, addr + i, 0xFF, buf[i]);
+ if (retval != STATUS_SUCCESS) {
+ vfree(buf);
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+
+ vfree(buf);
+ scsi_set_resid(srb, scsi_bufflen(srb) - len);
+
+ return TRANSPORT_GOOD;
+}
+
+static int get_sd_csd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct sd_info *sd_card = &(chip->sd_card);
+ unsigned int lun = SCSI_LUN(srb);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (get_lun_card(chip, lun) != SD_CARD) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ scsi_set_resid(srb, 0);
+ rts51x_set_xfer_buf(sd_card->raw_csd, scsi_bufflen(srb), srb);
+
+ return TRANSPORT_GOOD;
+}
+
+static int read_phy_register(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int retval;
+ u8 addr, len, i;
+ u8 *buf;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ addr = srb->cmnd[5];
+ len = srb->cmnd[7];
+
+ if (len) {
+ buf = (u8 *)vmalloc(len);
+ if (!buf) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ for (i = 0; i < len; i++) {
+ retval = rts51x_read_phy_register(chip, addr + i, buf + i);
+ if (retval != STATUS_SUCCESS) {
+ vfree(buf);
+ set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+
+ len = min(scsi_bufflen(srb), (unsigned int)len);
+ rts51x_set_xfer_buf(buf, len, srb);
+ scsi_set_resid(srb, scsi_bufflen(srb) - len);
+
+ vfree(buf);
+ }
+
+ return TRANSPORT_GOOD;
+}
+
+static int write_phy_register(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int retval;
+ u8 addr, len, i;
+ u8 *buf;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ addr = srb->cmnd[5];
+ len = srb->cmnd[7];
+
+ if (len) {
+ len = min(scsi_bufflen(srb), (unsigned int)len);
+
+ buf = (u8 *)vmalloc(len);
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ rts51x_get_xfer_buf(buf, len, srb);
+ scsi_set_resid(srb, scsi_bufflen(srb) - len);
+
+ for (i = 0; i < len; i++) {
+ retval = rts51x_write_phy_register(chip, addr + i, buf[i]);
+ if (retval != STATUS_SUCCESS) {
+ vfree(buf);
+ set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+
+ vfree(buf);
+ }
+
+ return TRANSPORT_GOOD;
+}
+
+static int get_card_bus_width(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ u8 card, bus_width;
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ card = get_lun_card(chip, lun);
+ if ((card == SD_CARD) || (card == MS_CARD)) {
+ bus_width = chip->card_bus_width[lun];
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ scsi_set_resid(srb, 0);
+ rts51x_set_xfer_buf(&bus_width, scsi_bufflen(srb), srb);
+
+ return TRANSPORT_GOOD;
+}
+
+#ifdef _MSG_TRACE
+static int trace_msg_cmd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned char *buf = NULL;
+ u8 clear;
+ unsigned int buf_len;
+
+ buf_len = 4 + ((2 + MSG_FUNC_LEN + MSG_FILE_LEN + TIME_VAL_LEN) * TRACE_ITEM_CNT);
+
+ if ((scsi_bufflen(srb) < buf_len) || (scsi_sglist(srb) == NULL)) {
+ set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ clear = srb->cmnd[2];
+
+ buf = (unsigned char *)vmalloc(scsi_bufflen(srb));
+ if (buf == NULL) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ rts51x_trace_msg(chip, buf, clear);
+
+ rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
+ vfree(buf);
+
+ scsi_set_resid(srb, 0);
+ return TRANSPORT_GOOD;
+}
+#endif
+
+static int rw_mem_cmd_buf(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int retval = STATUS_SUCCESS;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 cmd_type, mask, value, idx, mode, len;
+ u16 addr;
+ u32 timeout;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ switch (srb->cmnd[3]) {
+ case INIT_BATCHCMD:
+ rts51x_init_cmd(chip);
+ break;
+
+ case ADD_BATCHCMD:
+ cmd_type = srb->cmnd[4];
+ if (cmd_type > 2) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ addr = (srb->cmnd[5] << 8) | srb->cmnd[6];
+ mask = srb->cmnd[7];
+ value = srb->cmnd[8];
+ rts51x_add_cmd(chip, cmd_type, addr, mask, value);
+ break;
+
+ case SEND_BATCHCMD:
+ mode = srb->cmnd[4];
+ len = srb->cmnd[5];
+ timeout = ((u32)srb->cmnd[6] << 24) | ((u32)srb->cmnd[7] << 16) |
+ ((u32)srb->cmnd[8] << 8) | ((u32)srb->cmnd[9]);
+ retval = rts51x_send_cmd(chip, mode, 1000);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ if (mode & STAGE_R) {
+ retval = rts51x_get_rsp(chip, len, timeout);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+ break;
+
+ case GET_BATCHRSP:
+ idx = srb->cmnd[4];
+ value = chip->rsp_buf[idx];
+ if (scsi_bufflen(srb) < 1) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ rts51x_set_xfer_buf(&value, 1, srb);
+ scsi_set_resid(srb, 0);
+ break;
+
+ default:
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ return TRANSPORT_GOOD;
+}
+
+static int suit_cmd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int result;
+
+ switch (srb->cmnd[3]) {
+ case INIT_BATCHCMD:
+ case ADD_BATCHCMD:
+ case SEND_BATCHCMD:
+ case GET_BATCHRSP:
+ result = rw_mem_cmd_buf(srb, chip);
+ break;
+ default:
+ result = TRANSPORT_ERROR;
+ }
+
+ return result;
+}
+
+static int app_cmd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int result;
+
+ switch (srb->cmnd[2]) {
+ case PP_READ10:
+ case PP_WRITE10:
+ result = read_write(srb, chip);
+ break;
+
+ case SUIT_CMD:
+ result = suit_cmd(srb, chip);
+ break;
+
+ case READ_PHY:
+ result = read_phy_register(srb, chip);
+ break;
+
+ case WRITE_PHY:
+ result = write_phy_register(srb, chip);
+ break;
+
+ case GET_DEV_STATUS:
+ result = get_dev_status(srb, chip);
+ break;
+
+ default:
+ set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ return result;
+}
+
+static int vendor_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int result = TRANSPORT_GOOD;
+
+ switch (srb->cmnd[1]) {
+ case READ_STATUS:
+ result = read_status(srb, chip);
+ break;
+
+ case READ_MEM:
+ result = read_mem(srb, chip);
+ break;
+
+ case WRITE_MEM:
+ result = write_mem(srb, chip);
+ break;
+
+ case GET_BUS_WIDTH:
+ result = get_card_bus_width(srb, chip);
+ break;
+
+ case GET_SD_CSD:
+ result = get_sd_csd(srb, chip);
+ break;
+
+#ifdef _MSG_TRACE
+ case TRACE_MSG:
+ result = trace_msg_cmd(srb, chip);
+ break;
+#endif
+
+ case SCSI_APP_CMD:
+ result = app_cmd(srb, chip);
+ break;
+
+ default:
+ set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ return result;
+}
+
+static int ms_format_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ unsigned int lun = SCSI_LUN(srb);
+ int retval, quick_format;
+
+ if (get_lun_card(chip, lun) != MS_CARD) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if ((srb->cmnd[3] != 0x4D) || (srb->cmnd[4] != 0x47) || (srb->cmnd[5] != 0x66) ||
+ (srb->cmnd[6] != 0x6D) || (srb->cmnd[7] != 0x74)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (srb->cmnd[8] & 0x01) {
+ quick_format = 0;
+ } else {
+ quick_format = 1;
+ }
+
+ if (!(chip->card_ready & MS_CARD)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (chip->card_wp & MS_CARD) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (!CHK_MSPRO(ms_card)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ retval = mspro_format(srb, chip, MS_SHORT_DATA_LEN, quick_format);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_FORMAT_CMD_FAILED);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ scsi_set_resid(srb, 0);
+ return TRANSPORT_GOOD;
+}
+
+#ifdef SUPPORT_PCGL_1P18
+int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ unsigned int lun = SCSI_LUN(srb);
+ u8 dev_info_id, data_len;
+ u8 *buf;
+ unsigned int buf_len;
+ int i;
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ if ((get_lun_card(chip, lun) != MS_CARD)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if ((srb->cmnd[2] != 0xB0) || (srb->cmnd[4] != 0x4D) ||
+ (srb->cmnd[5] != 0x53) || (srb->cmnd[6] != 0x49) ||
+ (srb->cmnd[7] != 0x44)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ dev_info_id = srb->cmnd[3];
+ if ((CHK_MSXC(ms_card) && (dev_info_id == 0x10)) ||
+ (!CHK_MSXC(ms_card) && (dev_info_id == 0x13)) ||
+ !CHK_MSPRO(ms_card)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (dev_info_id == 0x15) {
+ buf_len = data_len = 0x3A;
+ } else {
+ buf_len = data_len = 0x6A;
+ }
+
+ buf = (u8 *)kmalloc(buf_len, GFP_KERNEL);
+ if (!buf) {
+ TRACE_RET(chip, TRANSPORT_ERROR);
+ }
+
+ i = 0;
+ buf[i++] = 0x00;
+ buf[i++] = data_len;
+ if (CHK_MSXC(ms_card)) {
+ buf[i++] = 0x03;
+ } else {
+ buf[i++] = 0x02;
+ }
+ buf[i++] = 0x01;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x01;
+
+ buf[i++] = dev_info_id;
+ if (dev_info_id == 0x15) {
+ data_len = 0x31;
+ } else {
+ data_len = 0x61;
+ }
+ buf[i++] = 0x00;
+ buf[i++] = data_len;
+ buf[i++] = 0x80;
+ if ((dev_info_id == 0x10) || (dev_info_id == 0x13)) {
+ memcpy(buf+i, ms_card->raw_sys_info, 96);
+ } else {
+ memcpy(buf+i, ms_card->raw_model_name, 48);
+ }
+
+ rts51x_set_xfer_buf(buf, buf_len, srb);
+
+ if (dev_info_id == 0x15) {
+ scsi_set_resid(srb, scsi_bufflen(srb)-0x3C);
+ } else {
+ scsi_set_resid(srb, scsi_bufflen(srb)-0x6C);
+ }
+
+ kfree(buf);
+ return STATUS_SUCCESS;
+}
+#endif
+
+static int ms_sp_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int retval = TRANSPORT_ERROR;
+
+ if (srb->cmnd[2] == MS_FORMAT) {
+ retval = ms_format_cmnd(srb, chip);
+ }
+#ifdef SUPPORT_PCGL_1P18
+ else if (srb->cmnd[2] == GET_MS_INFORMATION) {
+ retval = get_ms_information(srb, chip);
+ }
+#endif
+
+ return retval;
+}
+
+#ifdef SUPPORT_CPRM
+static int sd_extention_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ unsigned int lun = SCSI_LUN(srb);
+ int result;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ sd_cleanup_work(chip);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ if ((get_lun_card(chip, lun) != SD_CARD)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ switch (srb->cmnd[0]) {
+ case SD_PASS_THRU_MODE:
+ result = sd_pass_thru_mode(srb, chip);
+ break;
+
+ case SD_EXECUTE_NO_DATA:
+ result = sd_execute_no_data(srb, chip);
+ break;
+
+ case SD_EXECUTE_READ:
+ result = sd_execute_read_data(srb, chip);
+ break;
+
+ case SD_EXECUTE_WRITE:
+ result = sd_execute_write_data(srb, chip);
+ break;
+
+ case SD_GET_RSP:
+ result = sd_get_cmd_rsp(srb, chip);
+ break;
+
+ case SD_HW_RST:
+ result = sd_hw_rst(srb, chip);
+ break;
+
+ default:
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ return result;
+}
+#endif
+
+#ifdef SUPPORT_MAGIC_GATE
+int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ unsigned int lun = SCSI_LUN(srb);
+ int retval;
+ u8 key_format;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ ms_cleanup_work(chip);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ if ((get_lun_card(chip, lun) != MS_CARD)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (srb->cmnd[7] != KC_MG_R_PRO) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (!CHK_MSPRO(ms_card)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ key_format = srb->cmnd[10] & 0x3F;
+
+ switch (key_format) {
+ case KF_GET_LOC_EKB:
+ if ((scsi_bufflen(srb) == 0x41C) &&
+ (srb->cmnd[8] == 0x04) &&
+ (srb->cmnd[9] == 0x1C))
+ {
+ retval = mg_get_local_EKB(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ break;
+
+ case KF_RSP_CHG:
+ if ((scsi_bufflen(srb) == 0x24) &&
+ (srb->cmnd[8] == 0x00) &&
+ (srb->cmnd[9] == 0x24))
+ {
+ retval = mg_get_rsp_chg(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ break;
+
+ case KF_GET_ICV:
+ ms_card->mg_entry_num = srb->cmnd[5];
+ if ((scsi_bufflen(srb) == 0x404) &&
+ (srb->cmnd[8] == 0x04) &&
+ (srb->cmnd[9] == 0x04) &&
+ (srb->cmnd[2] == 0x00) &&
+ (srb->cmnd[3] == 0x00) &&
+ (srb->cmnd[4] == 0x00) &&
+ (srb->cmnd[5] < 32))
+ {
+ retval = mg_get_ICV(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ 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;
+}
+
+int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ unsigned int lun = SCSI_LUN(srb);
+ int retval;
+ u8 key_format;
+
+ rts51x_prepare_run(chip);
+ RTS51X_SET_STAT(chip, STAT_RUN);
+
+ ms_cleanup_work(chip);
+
+ if (!check_card_ready(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ if (check_card_wp(chip, lun)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ if ((get_lun_card(chip, lun) != MS_CARD)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (srb->cmnd[7] != KC_MG_R_PRO) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ if (!CHK_MSPRO(ms_card)) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+
+ key_format = srb->cmnd[10] & 0x3F;
+
+ switch (key_format) {
+ case KF_SET_LEAF_ID:
+ if ((scsi_bufflen(srb) == 0x0C) &&
+ (srb->cmnd[8] == 0x00) &&
+ (srb->cmnd[9] == 0x0C))
+ {
+ retval = mg_set_leaf_id(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ break;
+
+ case KF_CHG_HOST:
+ if ((scsi_bufflen(srb) == 0x0C) &&
+ (srb->cmnd[8] == 0x00) &&
+ (srb->cmnd[9] == 0x0C))
+ {
+ retval = mg_chg(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ break;
+
+ case KF_RSP_HOST:
+ if ((scsi_bufflen(srb) == 0x0C) &&
+ (srb->cmnd[8] == 0x00) &&
+ (srb->cmnd[9] == 0x0C))
+ {
+ retval = mg_rsp(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ break;
+
+ case KF_SET_ICV:
+ ms_card->mg_entry_num = srb->cmnd[5];
+ if ((scsi_bufflen(srb) == 0x404) &&
+ (srb->cmnd[8] == 0x04) &&
+ (srb->cmnd[9] == 0x04) &&
+ (srb->cmnd[2] == 0x00) &&
+ (srb->cmnd[3] == 0x00) &&
+ (srb->cmnd[4] == 0x00) &&
+ (srb->cmnd[5] < 32))
+ {
+ retval = mg_set_ICV(srb, chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ 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
+
+int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+#ifdef SUPPORT_SD_LOCK
+ struct sd_info *sd_card = &(chip->sd_card);
+#endif
+ struct ms_info *ms_card = &(chip->ms_card);
+ unsigned int lun = SCSI_LUN(srb);
+ int result = TRANSPORT_GOOD;
+
+#ifdef SUPPORT_SD_LOCK
+ if (sd_card->sd_erase_status) {
+ if (!((srb->cmnd[0] == VENDOR_CMND) && (srb->cmnd[1] == SCSI_APP_CMD) &&
+ (srb->cmnd[2] == GET_DEV_STATUS)) &&
+ (srb->cmnd[0] != REQUEST_SENSE)) {
+ set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0);
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+#endif
+
+ if ((get_lun_card(chip, lun) == MS_CARD) &&
+ (ms_card->format_status == FORMAT_IN_PROGRESS)) {
+ if ((srb->cmnd[0] != REQUEST_SENSE) && (srb->cmnd[0] != INQUIRY)) {
+ set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04,
+ 0, (u16)(ms_card->progress));
+ TRACE_RET(chip, TRANSPORT_FAILED);
+ }
+ }
+
+ switch (srb->cmnd[0]) {
+ case READ_10:
+ case WRITE_10:
+ case READ_6:
+ case WRITE_6:
+ result = read_write(srb, chip);
+ break;
+
+ case TEST_UNIT_READY:
+ result = test_unit_ready(srb, chip);
+ break;
+
+ case INQUIRY:
+ result = inquiry(srb, chip);
+ break;
+
+ case READ_CAPACITY:
+ result = read_capacity(srb, chip);
+ break;
+
+ case START_STOP:
+ result = start_stop_unit(srb, chip);
+ break;
+
+ case ALLOW_MEDIUM_REMOVAL:
+ result = allow_medium_removal(srb, chip);
+ break;
+
+ case REQUEST_SENSE:
+ result = request_sense(srb, chip);
+ break;
+
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ result = mode_sense(srb, chip);
+ break;
+
+ case 0x23:
+ result = read_format_capacity(srb, chip);
+ break;
+
+ case VENDOR_CMND:
+ result = vendor_cmnd(srb, chip);
+ break;
+
+ case MS_SP_CMND:
+ result = ms_sp_cmnd(srb, chip);
+ break;
+
+#ifdef SUPPORT_CPRM
+ case SD_PASS_THRU_MODE:
+ case SD_EXECUTE_NO_DATA:
+ case SD_EXECUTE_READ:
+ case SD_EXECUTE_WRITE:
+ case SD_GET_RSP:
+ case SD_HW_RST:
+ result = sd_extention_cmnd(srb, chip);
+ break;
+#endif
+
+#ifdef SUPPORT_MAGIC_GATE
+ case CMD_MSPRO_MG_RKEY:
+ result = mg_report_key(srb, chip);
+ break;
+
+ case CMD_MSPRO_MG_SKEY:
+ result = mg_send_key(srb, chip);
+ break;
+#endif
+
+ case FORMAT_UNIT:
+ case MODE_SELECT:
+ case VERIFY:
+ result = TRANSPORT_GOOD;
+ break;
+
+ default:
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ result = TRANSPORT_FAILED;
+ }
+
+ return result;
+}