📄 ftl.patch
字号:
+ NULL, /* readdir */+ NULL, /* poll */+ ftl_ioctl, /* ioctl */+ NULL, /* mmap */+ ftl_open, /* open */+ NULL, /* flush */+ ftl_close, /* release */+ block_fsync /* fsync */+};++/*======================================================================++ Scan_header() checks to see if a memory region contains an FTL+ partition. build_maps() reads all the erase unit headers, builds+ the erase unit map, and then builds the virtual page map.++======================================================================*/++static int scan_header(ftl_dev_t *dev)+{+ erase_unit_header_t header;+ off_t offset;+ size_t count;+ int ret;++ DEBUG("scan_header(%p)\n", dev);++ /* Search first megabyte for a valid FTL header */+ count = sizeof(header);+ for (offset = 0;+ offset < 0x100000;+ offset += dev->region.BlockSize) {+ ret = (*dev->flash->ops->read)(dev->flash, (char *)&header,+ count, offset + dev->base_offset, 0);+ if (ret) {+ printk("Error reading flash mem.\n");+ return -1;+ }+ if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;+ }+ if (offset == 0x100000) {+ printk(KERN_NOTICE "ftl: FTL header not found.\n");+ return -1;+ }+ if ((header.NumEraseUnits > 65536) || (header.BlockSize != 9) ||+ (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||+ (header.NumTransferUnits >= header.NumEraseUnits)) {+ printk(KERN_NOTICE "ftl: FTL header corrupt!\n");+ return -1;+ }+ dev->header = header;+ return 0;+}++static int build_maps(ftl_dev_t *dev)+{+ erase_unit_header_t header;+ u_short xvalid, xtrans, i;+ u_int blocks, j;+ int hdr_ok, ret;+ size_t count;+ off_t offset;++ DEBUG("build_maps(%p)\n", dev);++ /* Set up erase unit maps */+ dev->DataUnits = dev->header.NumEraseUnits - dev->header.NumTransferUnits;+ dev->EUNInfo = kmalloc(dev->DataUnits * sizeof(struct eun_info_t), GFP_KERNEL);+ for (i = 0; i < dev->DataUnits; i++)+ dev->EUNInfo[i].Offset = 0xffffffff;+ dev->XferInfo =+ kmalloc(dev->header.NumTransferUnits * sizeof(struct xfer_info_t), GFP_KERNEL);++ count = sizeof(header);+ xvalid = xtrans = 0;+ for (i = 0; i < dev->header.NumEraseUnits; i++) {+ offset = ((i + dev->header.FirstPhysicalEUN)+ << dev->header.EraseUnitSize);+ ret = (*dev->flash->ops->read)(dev->flash, (char *)&header,+ count, offset + dev->base_offset, 0);+ if (ret) {+ printk("Error reading flash mem.\n");+ return -1;+ }+ /* Is this a transfer partition? */+ hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);+ if (hdr_ok && (header.LogicalEUN < dev->DataUnits) &&+ (dev->EUNInfo[header.LogicalEUN].Offset == 0xffffffff)) {+ dev->EUNInfo[header.LogicalEUN].Offset = offset;+ dev->EUNInfo[header.LogicalEUN].EraseCount = header.EraseCount;+ xvalid++;+ } else {+ if (xtrans == dev->header.NumTransferUnits) {+ printk(KERN_NOTICE+ "ftl: format error: too many transfer units!\n");+ return -1;+ }+ if (hdr_ok && (header.LogicalEUN == 0xffff)) {+ dev->XferInfo[xtrans].state = XFER_PREPARED;+ dev->XferInfo[xtrans].EraseCount = header.EraseCount;+ } else {+ dev->XferInfo[xtrans].state = XFER_UNKNOWN;+ /* Pick anything reasonable for the erase count */+ dev->XferInfo[xtrans].EraseCount =+ dev->header.EraseCount;+ }+ dev->XferInfo[xtrans].Offset = offset;+ xtrans++;+ }+ }+ /* Check for format trouble */+ header = dev->header;+ if ((xtrans != header.NumTransferUnits) ||+ (xvalid+xtrans != header.NumEraseUnits)) {+ printk(KERN_NOTICE "cs: format error: erase units don't add up!\n");+ return -1;+ }++ /* Set up virtual page map */+ blocks = header.FormattedSize >> header.BlockSize;+ dev->VirtualBlockMap = vmalloc(blocks * sizeof(u_int));+ memset(dev->VirtualBlockMap, 0xff, blocks * sizeof(u_int));+ dev->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;+ count = dev->BlocksPerUnit * sizeof(u_int);++ dev->bam_cache = kmalloc(dev->BlocksPerUnit * sizeof(u_int), GFP_KERNEL);+ dev->bam_index = 0xffff;+ dev->FreeTotal = 0;+ for (i = 0; i < dev->DataUnits; i++) {+ dev->EUNInfo[i].Free = 0;+ dev->EUNInfo[i].Deleted = 0;+ offset = dev->EUNInfo[i].Offset + header.BAMOffset;+ ret = (*dev->flash->ops->read)(dev->flash, (char *)dev->bam_cache,+ count, offset + dev->base_offset, 0);+ if (ret) {+ printk("Error reading flash mem.\n");+ return -1;+ }+ for (j = 0; j < dev->BlocksPerUnit; j++) {+ if (BLOCK_FREE(dev->bam_cache[j])) {+ dev->EUNInfo[i].Free++;+ dev->FreeTotal++;+ } else if ((BLOCK_TYPE(dev->bam_cache[j]) == BLOCK_DATA) &&+ (BLOCK_NUMBER(dev->bam_cache[j]) < blocks)) {+ dev->VirtualBlockMap[BLOCK_NUMBER(dev->bam_cache[j])] =+ (i << header.EraseUnitSize) + (j << header.BlockSize);+ } else if (BLOCK_DELETED(dev->bam_cache[j])) {+ dev->EUNInfo[i].Deleted++;+ }+ }+ }++ return 0;++} /* build_maps */++/*======================================================================++ Erase_xfer() schedules an asynchronous erase operation for a+ transfer unit.++======================================================================*/++static int erase_xfer(ftl_dev_t *dev, u_short xfernum)+{+ int ret;+ struct xfer_info_t *xfer;+ off_t offset;+ size_t count;++ xfer = &dev->XferInfo[xfernum];+ DEBUG("ftl: erasing xfer unit at 0x%x\n", xfer->Offset);+ xfer->state = XFER_ERASING;++#if 0+ /* Is there a free erase slot? */+ for (;;) {+ for (i = 0; i < MAX_ERASE; i++)+ if (!ERASE_IN_PROGRESS(dev->eraseq[i].State)) break;+ if (i < MAX_ERASE) break;+ DEBUG("ftl_cs: erase queue is full\n");+ sleep_on(&dev->erase_pending);+ }++ /* Queue the request */+ dev->eraseq[i].State = ERASE_QUEUED;+ dev->eraseq[i].Handle = part->handle;+ dev->eraseq[i].Offset = xfer->Offset;+ dev->eraseq[i].Size = part->region.BlockSize;+ dev->eraseq[i].Optional = part;+ ret = CardServices(CheckEraseQueue, dev->eraseq_handle);+ if (ret != CS_SUCCESS) {+ cs_error(CheckEraseQueue, ret);+ return -EIO;+ }+#endif /* 0 */++ offset = xfer->Offset;+ count = dev->region.BlockSize;++ ret = (*dev->flash->ops->erase_sector)(dev->flash,+ offset + dev->base_offset, count);+ if (ret) {+ xfer->state = XFER_FAILED;+ printk("Error erasing flash mem.\n");+ return -EIO;+ } else {+ xfer->state = XFER_ERASED;+ }++ xfer->EraseCount++;+ return ret;+} /* erase_xfer */+++#if 0+static void save_status(eraseq_entry_t *erase)+{+ partition_t *part;+ struct xfer_info_t *xfer;+ int i;++ /* Look up the transfer unit */+ part = (partition_t *)(erase->Optional);+ for (i = 0; i < part->header.NumTransferUnits; i++)+ if (part->XferInfo[i].Offset == erase->Offset) break;+ if (i == part->header.NumTransferUnits) {+ printk(KERN_NOTICE "ftl_cs: internal error: "+ "erase lookup failed!\n");+ return;+ }+ xfer = &part->XferInfo[i];+ if (erase->State == ERASE_PASSED)+ xfer->state = XFER_ERASED;+ else {+ xfer->state = XFER_FAILED;+ printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",+ erase->State);+ }+}+#endif /* 0 */++/*======================================================================++ Prepare_xfer() takes a freshly erased transfer unit and gives+ it an appropriate header.++======================================================================*/++static void prepare_xfer(ftl_dev_t *dev, int i)+{+ erase_unit_header_t header;+ struct xfer_info_t *xfer;+ int nbam, ret;+ u_int ctl;+ off_t offset;+ size_t count;++ xfer = &dev->XferInfo[i];+ xfer->state = XFER_FAILED;++ DEBUG("ftl: preparing xfer unit at 0x%x\n", xfer->Offset);++ /* Write the transfer unit header */+ header = dev->header;+ header.LogicalEUN = 0xffff;+ header.EraseCount = xfer->EraseCount;+ count = sizeof(header);+ offset = xfer->Offset;+ ret = (*dev->flash->ops->write)(dev->flash, (char *)&header,+ count, offset + dev->base_offset, 0);+ if (ret) {+ printk("Error writing flash mem.\n");+ return;+ }++ /* Write the BAM stub */+ nbam = (dev->BlocksPerUnit * sizeof(u_int) ++ dev->header.BAMOffset + SECTOR_SIZE - 1) / SECTOR_SIZE;+ offset = xfer->Offset + dev->header.BAMOffset;+ count = sizeof(u_int);+ ctl = BLOCK_CONTROL;+ for (i = 0; i < nbam; i++, offset += sizeof(u_int)) {+ ret = (*dev->flash->ops->write)(dev->flash, (char *)&ctl,+ count, offset + dev->base_offset, 0);+ if (ret) {+ printk("Error writing flash mem.\n");+ return;+ }+ }+ xfer->state = XFER_PREPARED;++} /* prepare_xfer */++/*======================================================================++ Copy_erase_unit() takes a full erase block and a transfer unit,+ copies everything to the transfer unit, then swaps the block+ pointers.++ All data blocks are copied to the corresponding blocks in the+ target unit, so the virtual block map does not need to be+ updated.++======================================================================*/++static int copy_erase_unit(ftl_dev_t *dev, u_short srcunit, u_short xferunit)+{+ u_char buf[SECTOR_SIZE];+ struct eun_info_t *eun;+ struct xfer_info_t *xfer;+ u_int src, dest, free, i;+ u_short unit;+ int ret;+ off_t offset;+ size_t count;++ eun = &dev->EUNInfo[srcunit];+ xfer = &dev->XferInfo[xferunit];++ DEBUG("ftl: copying block 0x%x to 0x%x\n", eun->Offset, xfer->Offset);++ /* Read current BAM */+ if (dev->bam_index != srcunit) {+ offset = eun->Offset + dev->header.BAMOffset;+ count = dev->BlocksPerUnit * sizeof(u_int);+ ret = (*dev->flash->ops->read)(dev->flash, (char *)dev->bam_cache,+ count, offset + dev->base_offset, 0);+ /* mark the cache bad, in case we get an error later */+ dev->bam_index = 0xffff;+ if (ret)+ goto read_error;+ }++ /* Write the LogicalEUN for the transfer unit */+ xfer->state = XFER_UNKNOWN;+ count = sizeof(u_short);+ offset = xfer->Offset + 20; /* Bad! */+ unit = 0x7fff;+ ret = (*dev->flash->ops->write)(dev->flash, (char *)&unit,+ count, offset + dev->base_offset, 0);+ if (ret)+ goto write_error;++ /* Copy all data blocks from source unit to transfer unit */+ src = eun->Offset; dest = xfer->Offset;+ count = SECTOR_SIZE;+ free = 0;+ ret = 0;+ for (i = 0; i < dev->BlocksPerUnit; i++) {+ switch (BLOCK_TYPE(dev->bam_cache[i])) {+ case BLOCK_CONTROL:+ /* This gets updated later */+ break;+ case BLOCK_DATA:+ case BLOCK_REPLACEMENT:+ offset = src;+ ret = (*dev->flash->ops->read)(dev->flash, &buf[0],+ count, offset + dev->base_offset, 0);+ if (ret) goto read_error;+ offset = dest;+ ret = (*dev->flash->ops->write)(dev->flash, &buf[0],+ count, offset + dev->base_offset, 0);+ if (ret) goto write_error;+ break;+ default:+ /* All other blocks must be free */+ dev->bam_cache[i] = 0xffffffff;+ free++;+ break;+ }+ src += SECTOR_SIZE;+ dest += SECTOR_SIZE;+ }++ /* Write the BAM to the transfer unit */+ offset = xfer->Offset + dev->header.BAMOffset;+ count = dev->BlocksPerUnit * sizeof(u_int);+ ret = (*dev->flash->ops->write)(dev->flash, (char *)dev->bam_cache,+ count, offset + dev->base_offset, 0);+ if (ret) goto write_error;++ /* All clear? Then update the LogicalEUN again */+ offset = xfer->Offset + 20; /* Bad! */+ count = sizeof(u_short);+ ret = (*dev->flash->ops->write)(dev->flash, (char *)&srcunit,+ count, offset + dev->base_offset, 0);+ if (ret) goto write_error;++ /* Update the maps and usage stats*/+ i = xfer->EraseCount;+ xfer->EraseCount = eun->EraseCount;+ eun->EraseCount = i;+ i = xfer->Offset;+ xfer->Offset = eun->Offset;+ eun->Offset = i;+ dev->FreeTotal -= eun->Free;+ dev->FreeTotal += free;+ eun->Free = free;+ eun->Deleted = 0;++ /* Now, the cache should be valid for the new block */+ dev->bam_index = srcunit;++ return 0;++read_error:+ printk("Error reading flash mem.\n");+ return ret;++write_error:+ printk("Error writing flash mem.\n");+ return ret;+} /* copy_erase_unit */+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -