/* * Verifies if a request should be dispatched or not. * * Returns: * <0 in case of error. * 0 if request passes the checks */ static int sd_check_request(struct sd_host *host, struct request *req) { unsigned long nr_sectors; if (req->cmd_type != REQ_TYPE_FS) return -EIO; if (test_bit(__SD_MEDIA_CHANGED, &host->flags)) { sd_printk(KERN_ERR, "media changed, aborting\n"); return -ENOMEDIUM; } /* unit is kernel sectors */ nr_sectors = host->card.csd.capacity << (host->card.csd.read_blkbits - KERNEL_SECTOR_SHIFT); /* keep our reads within limits */ if ((blk_rq_pos(req) + blk_rq_cur_sectors(req)) > nr_sectors) { sd_printk(KERN_ERR, "reading past end, aborting\n"); return -EINVAL; } return 0; }
static int sd_welcome_card(struct sd_host *host) { int retval; /* soft reset the card */ retval = sd_reset_sequence(host); if (retval < 0 || sd_card_is_bad(host)) goto out; /* read Operating Conditions Register */ retval = sd_read_ocr(host); if (retval < 0) goto err_bad_card; /* refuse to drive cards reporting voltage ranges out of scope */ if (!(host->ocr & host->ocr_avail)) { sd_printk(KERN_WARNING, "reported OCR (%08x)" " indicates that it is not safe to use this" " card with a GameCube\n", host->ocr); retval = -ENODEV; goto err_bad_card; } /* read and decode the Card Specific Data */ retval = sd_read_csd(host); if (retval < 0) goto err_bad_card; mmc_decode_csd(&host->card); /* calculate some card access related timeouts */ sd_calc_timeouts(host); /* read and decode the Card Identification Data */ retval = sd_read_cid(host); if (retval < 0) goto err_bad_card; mmc_decode_cid(&host->card); sd_printk(KERN_INFO, "slot%d: descr \"%s\", size %luk, block %ub," " serial %08x\n", to_channel(exi_get_exi_channel(host->exi_device)), host->card.cid.prod_name, (unsigned long)((host->card.csd.capacity * (1 << host->card.csd.read_blkbits)) / 1024), 1 << host->card.csd.read_blkbits, host->card.cid.serial); retval = 0; goto out; err_bad_card: sd_card_set_bad(host); out: return retval; }
/* * Initializes the block layer interfaces. */ static int sd_init_blk_dev(struct sd_host *host) { struct gendisk *disk; struct request_queue *queue; int channel; int retval; channel = to_channel(exi_get_exi_channel(host->exi_device)); /* queue */ retval = -ENOMEM; spin_lock_init(&host->queue_lock); queue = blk_init_queue(sd_request_func, &host->queue_lock); if (!queue) { sd_printk(KERN_ERR, "error initializing queue\n"); goto err_blk_init_queue; } blk_queue_dma_alignment(queue, EXI_DMA_ALIGN); blk_queue_max_phys_segments(queue, 1); blk_queue_max_hw_segments(queue, 1); blk_queue_max_sectors(queue, 8); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, queue); queue->queuedata = host; host->queue = queue; /* disk */ disk = alloc_disk(1 << MMC_SHIFT); if (!disk) { sd_printk(KERN_ERR, "error allocating disk\n"); goto err_alloc_disk; } disk->major = SD_MAJOR; disk->first_minor = channel << MMC_SHIFT; disk->fops = &sd_fops; sprintf(disk->disk_name, "%s%c", SD_NAME, 'a' + channel); disk->private_data = host; disk->queue = host->queue; host->disk = disk; retval = 0; goto out; err_alloc_disk: blk_cleanup_queue(host->queue); host->queue = NULL; err_blk_init_queue: out: return retval; }
/* * ubicom32sd_mmc_get_cd */ static int ubicom32sd_mmc_get_cd(struct mmc_host *mmc) { struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); sd_printk("%s: get cd %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_cd, gpio_get_value(ud->pdata->cards[0].pin_cd)); return gpio_get_value(ud->pdata->cards[0].pin_cd) ? ud->pdata->cards[0].cd_polarity : !ud->pdata->cards[0].cd_polarity; }
static int __init sd_init_module(void) { int retval = 0; sd_printk(KERN_INFO, "%s - version %s\n", DRV_DESCRIPTION, sd_driver_version); if (register_blkdev(SD_MAJOR, DRV_MODULE_NAME)) { sd_printk(KERN_ERR, "unable to register major %d\n", SD_MAJOR); retval = -EIO; goto out; } retval = exi_driver_register(&sd_driver); out: return retval; }
/* * ubicom32sd_mmc_set_ios */ static void ubicom32sd_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); u32_t command = SDTIO_COMMAND_SETUP << SDTIO_COMMAND_SHIFT; u32_t arg = 0; sd_printk("%s: ios call bw:%u pm:%u clk:%u\n", mmc_hostname(mmc), 1 << ios->bus_width, ios->power_mode, ios->clock); switch (ios->bus_width) { case MMC_BUS_WIDTH_1: command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_1BIT; break; case MMC_BUS_WIDTH_4: command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_4BIT; break; } if (ios->clock) { arg = ios->clock; command |= SDTIO_COMMAND_FLAG_SET_CLOCK; } switch (ios->power_mode) { /* * Turn off the SD bus (power + clock) */ case MMC_POWER_OFF: gpio_set_value(ud->pdata->cards[0].pin_pwr, !ud->pdata->cards[0].pwr_polarity); command |= SDTIO_COMMAND_FLAG_SET_CLOCK; break; /* * Turn on the power to the SD bus */ case MMC_POWER_ON: gpio_set_value(ud->pdata->cards[0].pin_pwr, ud->pdata->cards[0].pwr_polarity); break; /* * Turn on the clock to the SD bus */ case MMC_POWER_UP: /* * Done above */ break; } ubicom32sd_send_command_sync(ud, command, arg); /* * Let the power settle down */ udelay(500); }
/* * Configure exchange of protection information between OS and HBA. */ void sd_dif_config_host(struct scsi_disk *sdkp) { struct scsi_device *sdp = sdkp->device; struct gendisk *disk = sdkp->disk; u8 type = sdkp->protection_type; int dif, dix; dif = scsi_host_dif_capable(sdp->host, type); dix = scsi_host_dix_capable(sdp->host, type); if (!dix && scsi_host_dix_capable(sdp->host, 0)) { dif = 0; dix = 1; } if (!dix) return; /* Enable DMA of protection information */ if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) if (type == SD_DIF_TYPE3_PROTECTION) blk_integrity_register(disk, &dif_type3_integrity_ip); else blk_integrity_register(disk, &dif_type1_integrity_ip); else if (type == SD_DIF_TYPE3_PROTECTION) blk_integrity_register(disk, &dif_type3_integrity_crc); else blk_integrity_register(disk, &dif_type1_integrity_crc); sd_printk(KERN_NOTICE, sdkp, "Enabling DIX %s protection\n", disk->integrity->name); /* Signal to block layer that we support sector tagging */ if (dif && type && sdkp->ATO) { if (type == SD_DIF_TYPE3_PROTECTION) disk->integrity->tag_size = sizeof(u16) + sizeof(u32); else disk->integrity->tag_size = sizeof(u16); sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", disk->integrity->tag_size); } }
/* * ubicom32sd_mmc_get_ro */ static int ubicom32sd_mmc_get_ro(struct mmc_host *mmc) { struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); if (ud->pdata->cards[0].pin_wp == -1) { return ud->pdata->cards[0].wp_polarity; } sd_printk("%s: get ro %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_wp, gpio_get_value(ud->pdata->cards[0].pin_wp)); return gpio_get_value(ud->pdata->cards[0].pin_wp) ? ud->pdata->cards[0].wp_polarity : !ud->pdata->cards[0].wp_polarity; }
/** * Issue a REPORT ZONES scsi command. */ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf, unsigned int buflen, sector_t lba) { struct scsi_device *sdp = sdkp->device; const int timeout = sdp->request_queue->rq_timeout; struct scsi_sense_hdr sshdr; unsigned char cmd[16]; unsigned int rep_len; int result; memset(cmd, 0, 16); cmd[0] = ZBC_IN; cmd[1] = ZI_REPORT_ZONES; put_unaligned_be64(lba, &cmd[2]); put_unaligned_be32(buflen, &cmd[10]); memset(buf, 0, buflen); result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, buf, buflen, &sshdr, timeout, SD_MAX_RETRIES, NULL); if (result) { sd_printk(KERN_ERR, sdkp, "REPORT ZONES lba %llu failed with %d/%d\n", (unsigned long long)lba, host_byte(result), driver_byte(result)); return -EIO; } rep_len = get_unaligned_be32(&buf[0]); if (rep_len < 64) { sd_printk(KERN_ERR, sdkp, "REPORT ZONES report invalid length %u\n", rep_len); return -EIO; } return 0; }
/* * Terminates a host. */ static void sd_kill(struct sd_host *host) { if (host->refcnt > 0) { sd_printk(KERN_ERR, "hey! card removed while in use!\n"); set_bit(__SD_MEDIA_CHANGED, &host->flags); } sd_exit(host); host->exi_device = NULL; /* release the host immediately when not in use */ if (!host->refcnt) kfree(host); }
static void sd_print_cid(struct mmc_cid *cid) { sd_printk(KERN_INFO, "manfid = %d\n" "oemid = %d\n" "prod_name = %s\n" "hwrev = %d\n" "fwrev = %d\n" "serial = %08x\n" "year = %d\n" "month = %d\n", cid->manfid, cid->oemid, cid->prod_name, cid->hwrev, cid->fwrev, cid->serial, cid->year, cid->month); }
/* * Initializes and launches the IO thread. */ static int sd_init_io_thread(struct sd_host *host) { int channel; int result = 0; channel = to_channel(exi_get_exi_channel(host->exi_device)); mutex_init(&host->io_mutex); host->io_thread = kthread_run(sd_io_thread, host, "ksdiod/%c", 'a' + channel); if (IS_ERR(host->io_thread)) { sd_printk(KERN_ERR, "error creating io thread\n"); result = PTR_ERR(host->io_thread); } return result; }
/* * Given a 128-bit response, decode to our card CSD structure. */ static void mmc_decode_csd(struct mmc_card *card) { struct mmc_csd *csd = &card->csd; unsigned int e, m, csd_struct; u32 *resp = card->raw_csd; /* * We only understand CSD structure v1.0, v1.1 and v2. * v2 has extra information in bits 15, 11 and 10. */ csd_struct = UNSTUFF_BITS(resp, 126, 2); if (csd_struct != 0 && csd_struct != 1 && csd_struct != 2) { sd_printk(KERN_ERR, "unrecognised CSD structure" " version %d\n", csd_struct); return; } csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); /* TAAC */ m = UNSTUFF_BITS(resp, 115, 4); e = UNSTUFF_BITS(resp, 112, 3); csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; /* NSAC */ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; /* TRAN_SPEED */ m = UNSTUFF_BITS(resp, 99, 4); e = UNSTUFF_BITS(resp, 96, 3); csd->max_dtr = tran_exp[e] * tran_mant[m]; /* CCC */ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); /* READ_BL_LEN */ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); /* C_SIZE */ m = UNSTUFF_BITS(resp, 62, 12); /* C_SIZE_MULT */ e = UNSTUFF_BITS(resp, 47, 3); csd->capacity = (1 + m) << (e + 2); /* in card blocks */ }
/* * ubicom32sd_interrupt */ static irqreturn_t ubicom32sd_interrupt(int irq, void *dev) { struct mmc_host *mmc = (struct mmc_host *)dev; struct mmc_request *mrq; struct ubicom32sd_data *ud; u32_t int_status; if (!mmc) { return IRQ_HANDLED; } ud = (struct ubicom32sd_data *)mmc_priv(mmc); if (!ud) { return IRQ_HANDLED; } int_status = ud->regs->int_status; ud->regs->int_status &= ~int_status; if (int_status & SDTIO_VP_INT_STATUS_SDIO_INT) { if (ud->int_en) { ud->int_pend = 0; mmc_signal_sdio_irq(mmc); } else { ud->int_pend++; } } if (!(int_status & SDTIO_VP_INT_STATUS_DONE)) { return IRQ_HANDLED; } mrq = ud->mrq; if (!mrq) { sd_printk("%s: Spurious interrupt", mmc_hostname(mmc)); return IRQ_HANDLED; } ud->mrq = NULL; /* * SDTIO_VP_INT_DONE */ if (mrq->cmd->flags & MMC_RSP_PRESENT) { struct mmc_command *cmd = mrq->cmd; cmd->error = 0; if ((cmd->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_CRC)) { cmd->error = -EILSEQ; sd_printk("%s:\t\t\tRSP CRC Error\n", mmc_hostname(mmc)); } else if (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT) { cmd->error = -ETIMEDOUT; sd_printk("%s:\t\t\tRSP Timeout\n", mmc_hostname(mmc)); goto done; } else if (cmd->flags & MMC_RSP_136) { cmd->resp[0] = ud->regs->cmd_rsp0; cmd->resp[1] = ud->regs->cmd_rsp1; cmd->resp[2] = ud->regs->cmd_rsp2; cmd->resp[3] = ud->regs->cmd_rsp3; } else { cmd->resp[0] = ud->regs->cmd_rsp0; } sd_printk("%s:\t\t\tResponse %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); } if (mrq->data) { struct mmc_data *data = mrq->data; if (int_status & SDTIO_VP_INT_STATUS_DATA_TIMEOUT) { data->error = -ETIMEDOUT; sd_printk("%s:\t\t\tData Timeout\n", mmc_hostname(mmc)); goto done; } else if (int_status & SDTIO_VP_INT_STATUS_DATA_CRC_ERR) { data->error = -EILSEQ; sd_printk("%s:\t\t\tData CRC\n", mmc_hostname(mmc)); goto done; } else if (int_status & SDTIO_VP_INT_STATUS_DATA_PROG_ERR) { data->error = -EILSEQ; sd_printk("%s:\t\t\tData Program Error\n", mmc_hostname(mmc)); goto done; } else { data->error = 0; data->bytes_xfered = ud->regs->data_bytes_transferred; } } if (mrq->stop && (mrq->stop->flags & MMC_RSP_PRESENT)) { struct mmc_command *stop = mrq->stop; stop->error = 0; if ((stop->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_CRC)) { stop->error = -EILSEQ; sd_printk("%s:\t\t\tStop RSP CRC Error\n", mmc_hostname(mmc)); } else if (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT) { stop->error = -ETIMEDOUT; sd_printk("%s:\t\t\tStop RSP Timeout\n", mmc_hostname(mmc)); goto done; } else if (stop->flags & MMC_RSP_136) { stop->resp[0] = ud->regs->stop_rsp0; stop->resp[1] = ud->regs->stop_rsp1; stop->resp[2] = ud->regs->stop_rsp2; stop->resp[3] = ud->regs->stop_rsp3; } else { stop->resp[0] = ud->regs->stop_rsp0; } sd_printk("%s:\t\t\tStop Response %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), stop->resp[0], stop->resp[1], stop->resp[2], stop->resp[3], stop->error); } done: mmc_request_done(mmc, mrq); return IRQ_HANDLED; }
/* * ubicom32sd_mmc_request */ static void ubicom32sd_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc); u32_t command = SDTIO_COMMAND_EXECUTE << SDTIO_COMMAND_SHIFT; int ret = 0; WARN(ud->mrq != NULL, "ud->mrq still set to %p\n", ud->mrq); //pr_debug("send cmd %08x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags); if (mrq->cmd) { struct mmc_command *cmd = mrq->cmd; sd_printk("%s:\t\t\tsetup cmd %02d arg %08x flags %08x\n", mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags); ud->regs->cmd_opcode = cmd->opcode; ud->regs->cmd_arg = cmd->arg; command |= SDTIO_COMMAND_FLAG_CMD; if (cmd->flags & MMC_RSP_PRESENT) { command |= SDTIO_COMMAND_FLAG_CMD_RSP; } if (cmd->flags & MMC_RSP_136) { command |= SDTIO_COMMAND_FLAG_CMD_RSP_136; } if (cmd->flags & MMC_RSP_CRC) { command |= SDTIO_COMMAND_FLAG_CMD_RSP_CRC; } } if (mrq->data) { struct mmc_data *data = mrq->data; struct scatterlist *sg = data->sg; int i; sd_printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, data->flags, data->timeout_ns); if (data->sg_len > SDTIO_MAX_SG_BLOCKS) { ret = -EINVAL; data->error = -EINVAL; goto fail; } ud->regs->data_timeout_ns = data->timeout_ns; ud->regs->data_blksz = data->blksz; ud->regs->data_blkct = data->blocks; ud->regs->sg_len = data->sg_len; /* * Load all of our sg list into the driver sg buffer */ for (i = 0; i < data->sg_len; i++) { sd_printk("%s: sg %d = %p %d\n", mmc_hostname(mmc), i, sg_virt(sg), sg->length); ud->regs->sg[i].addr = sg_virt(sg); ud->regs->sg[i].len = sg->length; if (((u32_t)ud->regs->sg[i].addr & 0x03) || (sg->length & 0x03)) { sd_printk("%s: Need aligned buffers\n", mmc_hostname(mmc)); ret = -EINVAL; data->error = -EINVAL; goto fail; } sg++; } if (data->flags & MMC_DATA_READ) { command |= SDTIO_COMMAND_FLAG_DATA_RD; } else if (data->flags & MMC_DATA_WRITE) { command |= SDTIO_COMMAND_FLAG_DATA_WR; } else if (data->flags & MMC_DATA_STREAM) { command |= SDTIO_COMMAND_FLAG_DATA_STREAM; } } if (mrq->stop) { struct mmc_command *stop = mrq->stop; sd_printk("%s: \t\t\tsetup stop %02d arg %08x flags %08x\n", mmc_hostname(mmc), stop->opcode, stop->arg, stop->flags); ud->regs->stop_opcode = stop->opcode; ud->regs->stop_arg = stop->arg; command |= SDTIO_COMMAND_FLAG_STOP_CMD; if (stop->flags & MMC_RSP_PRESENT) { command |= SDTIO_COMMAND_FLAG_STOP_RSP; } if (stop->flags & MMC_RSP_136) { command |= SDTIO_COMMAND_FLAG_STOP_RSP_136; } if (stop->flags & MMC_RSP_CRC) { command |= SDTIO_COMMAND_FLAG_STOP_RSP_CRC; } } ud->mrq = mrq; sd_printk("%s: Sending command %08x\n", mmc_hostname(mmc), command); ubicom32sd_send_command(ud, command, 0); return; fail: sd_printk("%s: mmcreq ret = %d\n", mmc_hostname(mmc), ret); mrq->cmd->error = ret; mmc_request_done(mmc, mrq); }
/* * Given the decoded CSD structure, decode the raw CID to our CID structure. */ static void mmc_decode_cid(struct mmc_card *card) { u32 *resp = card->raw_cid; memset(&card->cid, 0, sizeof(struct mmc_cid)); if (mmc_card_sd(card)) { card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4); card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4); card->cid.serial = UNSTUFF_BITS(resp, 24, 32); card->cid.year = UNSTUFF_BITS(resp, 12, 8); card->cid.month = UNSTUFF_BITS(resp, 8, 4); card->cid.year += 2000; } else { /* * The selection of the format here is guesswork based upon * information people have sent to date. */ switch (card->csd.mmca_vsn) { case 0: /* MMC v1.0 - v1.2 */ case 1: /* MMC v1.4 */ card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); card->cid.serial = UNSTUFF_BITS(resp, 16, 24); card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.year = UNSTUFF_BITS(resp, 8, 4); card->cid.year += 1997; break; case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); card->cid.serial = UNSTUFF_BITS(resp, 16, 32); card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.year = UNSTUFF_BITS(resp, 8, 4); card->cid.year += 1997; break; default: sd_printk(KERN_ERR, "card has unknown MMCA" " version %d\n", card->csd.mmca_vsn); break; } } }