in core/ms_block.c [335:463]
static int h_msb_read_page(struct memstick_dev *card,
struct memstick_request **out_mrq)
{
struct msb_data *msb = memstick_get_drvdata(card);
struct memstick_request *mrq = *out_mrq = &card->current_mrq;
struct scatterlist sg[2];
u8 command, intreg;
if (mrq->error) {
dbg("read_page, unknown error");
return msb_exit_state_machine(msb, mrq->error);
}
again:
switch (msb->state) {
case MSB_RP_SEND_BLOCK_ADDRESS:
/* msb_write_regs sometimes "fails" because it needs to update
* the reg window, and thus it returns request for that.
* Then we stay in this state and retry
*/
if (!msb_write_regs(msb,
offsetof(struct ms_register, param),
sizeof(struct ms_param_register),
(unsigned char *)&msb->regs.param))
return 0;
msb->state = MSB_RP_SEND_READ_COMMAND;
return 0;
case MSB_RP_SEND_READ_COMMAND:
command = MS_CMD_BLOCK_READ;
memstick_init_req(mrq, MS_TPC_SET_CMD, &command, 1);
msb->state = MSB_RP_SEND_INT_REQ;
return 0;
case MSB_RP_SEND_INT_REQ:
msb->state = MSB_RP_RECEIVE_INT_REQ_RESULT;
/* If dont actually need to send the int read request (only in
* serial mode), then just fall through
*/
if (msb_read_int_reg(msb, -1))
return 0;
fallthrough;
case MSB_RP_RECEIVE_INT_REQ_RESULT:
intreg = mrq->data[0];
msb->regs.status.interrupt = intreg;
if (intreg & MEMSTICK_INT_CMDNAK)
return msb_exit_state_machine(msb, -EIO);
if (!(intreg & MEMSTICK_INT_CED)) {
msb->state = MSB_RP_SEND_INT_REQ;
goto again;
}
msb->int_polling = false;
msb->state = (intreg & MEMSTICK_INT_ERR) ?
MSB_RP_SEND_READ_STATUS_REG : MSB_RP_SEND_OOB_READ;
goto again;
case MSB_RP_SEND_READ_STATUS_REG:
/* read the status register to understand source of the INT_ERR */
if (!msb_read_regs(msb,
offsetof(struct ms_register, status),
sizeof(struct ms_status_register)))
return 0;
msb->state = MSB_RP_RECEIVE_STATUS_REG;
return 0;
case MSB_RP_RECEIVE_STATUS_REG:
msb->regs.status = *(struct ms_status_register *)mrq->data;
msb->state = MSB_RP_SEND_OOB_READ;
fallthrough;
case MSB_RP_SEND_OOB_READ:
if (!msb_read_regs(msb,
offsetof(struct ms_register, extra_data),
sizeof(struct ms_extra_data_register)))
return 0;
msb->state = MSB_RP_RECEIVE_OOB_READ;
return 0;
case MSB_RP_RECEIVE_OOB_READ:
msb->regs.extra_data =
*(struct ms_extra_data_register *) mrq->data;
msb->state = MSB_RP_SEND_READ_DATA;
fallthrough;
case MSB_RP_SEND_READ_DATA:
/* Skip that state if we only read the oob */
if (msb->regs.param.cp == MEMSTICK_CP_EXTRA) {
msb->state = MSB_RP_RECEIVE_READ_DATA;
goto again;
}
sg_init_table(sg, ARRAY_SIZE(sg));
msb_sg_copy(msb->current_sg, sg, ARRAY_SIZE(sg),
msb->current_sg_offset,
msb->page_size);
memstick_init_req_sg(mrq, MS_TPC_READ_LONG_DATA, sg);
msb->state = MSB_RP_RECEIVE_READ_DATA;
return 0;
case MSB_RP_RECEIVE_READ_DATA:
if (!(msb->regs.status.interrupt & MEMSTICK_INT_ERR)) {
msb->current_sg_offset += msb->page_size;
return msb_exit_state_machine(msb, 0);
}
if (msb->regs.status.status1 & MEMSTICK_UNCORR_ERROR) {
dbg("read_page: uncorrectable error");
return msb_exit_state_machine(msb, -EBADMSG);
}
if (msb->regs.status.status1 & MEMSTICK_CORR_ERROR) {
dbg("read_page: correctable error");
msb->current_sg_offset += msb->page_size;
return msb_exit_state_machine(msb, -EUCLEAN);
} else {
dbg("read_page: INT error, but no status error bits");
return msb_exit_state_machine(msb, -EIO);
}
}
BUG();
}