Index: head/sys/arm/allwinner/aw_mmc.c =================================================================== --- head/sys/arm/allwinner/aw_mmc.c +++ head/sys/arm/allwinner/aw_mmc.c @@ -256,6 +256,8 @@ cts->proto_specific.mmc.host_f_min = sc->aw_host.f_min; cts->proto_specific.mmc.host_f_max = sc->aw_host.f_max; cts->proto_specific.mmc.host_caps = sc->aw_host.caps; + cts->proto_specific.mmc.host_max_data = (sc->aw_mmc_conf->dma_xferlen * + AW_MMC_DMA_SEGS) / MMC_SECTOR_SIZE; memcpy(&cts->proto_specific.mmc.ios, &sc->aw_host.ios, sizeof(struct mmc_ios)); ccb->ccb_h.status = CAM_REQ_CMP; break; Index: head/sys/cam/cam_ccb.h =================================================================== --- head/sys/cam/cam_ccb.h +++ head/sys/cam/cam_ccb.h @@ -1051,6 +1051,7 @@ #define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */ #define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */ uint32_t host_caps; + uint32_t host_max_data; }; /* Get/Set transfer rate/width/disconnection/tag queueing settings */ Index: head/sys/cam/mmc/mmc_da.c =================================================================== --- head/sys/cam/mmc/mmc_da.c +++ head/sys/cam/mmc/mmc_da.c @@ -1195,6 +1195,27 @@ return (cts->host_caps); } +static uint32_t +sdda_get_max_data(struct cam_periph *periph, union ccb *ccb) +{ + struct ccb_trans_settings_mmc *cts; + + cts = &ccb->cts.proto_specific.mmc; + memset(cts, 0, sizeof(struct ccb_trans_settings_mmc)); + + ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; + ccb->ccb_h.flags = CAM_DIR_NONE; + ccb->ccb_h.retry_count = 0; + ccb->ccb_h.timeout = 100; + ccb->ccb_h.cbfcnp = NULL; + xpt_action(ccb); + + if (ccb->ccb_h.status != CAM_REQ_CMP) + panic("Cannot get host max data"); + KASSERT(cts->host_max_data != 0, ("host_max_data == 0?!")); + return (cts->host_max_data); +} + static void sdda_start_init(void *context, union ccb *start_ccb) { @@ -1420,7 +1441,6 @@ struct sdda_softc *sc = (struct sdda_softc *)periph->softc; struct sdda_part *part; struct ccb_pathinq cpi; - u_int maxio; CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Partition type '%s', size %ju %s\n", @@ -1479,12 +1499,9 @@ part->disk->d_gone = sddadiskgonecb; part->disk->d_name = part->name; part->disk->d_drv1 = part; - maxio = cpi.maxio; /* Honor max I/O size of SIM */ - if (maxio == 0) - maxio = DFLTPHYS; /* traditional default */ - else if (maxio > MAXPHYS) - maxio = MAXPHYS; /* for safety */ - part->disk->d_maxsize = maxio; + part->disk->d_maxsize = + MIN(MAXPHYS, sdda_get_max_data(periph, + (union ccb *)&cpi) * mmc_get_sector_size(periph)); part->disk->d_unit = cnt; part->disk->d_flags = 0; strlcpy(part->disk->d_descr, sc->card_id_string, Index: head/sys/dev/sdhci/sdhci.c =================================================================== --- head/sys/dev/sdhci/sdhci.c +++ head/sys/dev/sdhci/sdhci.c @@ -2580,6 +2580,7 @@ case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts = &ccb->cts; + uint32_t max_data; if (sdhci_debug > 1) slot_printf(slot, "Got XPT_GET_TRAN_SETTINGS\n"); @@ -2593,6 +2594,19 @@ cts->proto_specific.mmc.host_f_min = slot->host.f_min; cts->proto_specific.mmc.host_f_max = slot->host.f_max; cts->proto_specific.mmc.host_caps = slot->host.caps; + /* + * Re-tuning modes 1 and 2 restrict the maximum data length + * per read/write command to 4 MiB. + */ + if (slot->opt & SDHCI_TUNING_ENABLED && + (slot->retune_mode == SDHCI_RETUNE_MODE_1 || + slot->retune_mode == SDHCI_RETUNE_MODE_2)) { + max_data = 4 * 1024 * 1024 / MMC_SECTOR_SIZE; + } else { + max_data = 65535; + } + cts->proto_specific.mmc.host_max_data = max_data; + memcpy(&cts->proto_specific.mmc.ios, &slot->host.ios, sizeof(struct mmc_ios)); ccb->ccb_h.status = CAM_REQ_CMP; break;