ssfdc.c (0870066d7e6c85bbe37741137e4c4731501a98e0) ssfdc.c (289c05222172b51401dbbb017115655f241d94ab)
1/*
2 * Linux driver for SSFDC Flash Translation Layer (Read only)
3 * © 2005 Eptar srl
4 * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
5 *
6 * Based on NTFL and MTDBLOCK_RO drivers
7 *
8 * This program is free software; you can redistribute it and/or modify

--- 121 unchanged lines hidden (view full) ---

130 if (ret < 0 || retlen != SECTOR_SIZE) {
131 printk(KERN_WARNING
132 "SSFDC_RO:can't read CIS/IDI sector\n");
133 } else if (!memcmp(sect_buf, cis_numbers,
134 sizeof(cis_numbers))) {
135 /* Found */
136 cis_sector = (int)(offset >> SECTOR_SHIFT);
137 } else {
1/*
2 * Linux driver for SSFDC Flash Translation Layer (Read only)
3 * © 2005 Eptar srl
4 * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
5 *
6 * Based on NTFL and MTDBLOCK_RO drivers
7 *
8 * This program is free software; you can redistribute it and/or modify

--- 121 unchanged lines hidden (view full) ---

130 if (ret < 0 || retlen != SECTOR_SIZE) {
131 printk(KERN_WARNING
132 "SSFDC_RO:can't read CIS/IDI sector\n");
133 } else if (!memcmp(sect_buf, cis_numbers,
134 sizeof(cis_numbers))) {
135 /* Found */
136 cis_sector = (int)(offset >> SECTOR_SHIFT);
137 } else {
138 DEBUG(MTD_DEBUG_LEVEL1,
139 "SSFDC_RO: CIS/IDI sector not found"
138 pr_debug("SSFDC_RO: CIS/IDI sector not found"
140 " on %s (mtd%d)\n", mtd->name,
141 mtd->index);
142 }
143 break;
144 }
145 }
146
147 kfree(sect_buf);

--- 68 unchanged lines hidden (view full) ---

216
217 /* Check for the signature bits in the address field (MSBits) */
218 if ((block_address & ~0x7FF) == 0x1000) {
219 parity = block_address & 0x01;
220 block_address &= 0x7FF;
221 block_address >>= 1;
222
223 if (get_parity(block_address, 10) != parity) {
139 " on %s (mtd%d)\n", mtd->name,
140 mtd->index);
141 }
142 break;
143 }
144 }
145
146 kfree(sect_buf);

--- 68 unchanged lines hidden (view full) ---

215
216 /* Check for the signature bits in the address field (MSBits) */
217 if ((block_address & ~0x7FF) == 0x1000) {
218 parity = block_address & 0x01;
219 block_address &= 0x7FF;
220 block_address >>= 1;
221
222 if (get_parity(block_address, 10) != parity) {
224 DEBUG(MTD_DEBUG_LEVEL0,
225 "SSFDC_RO: logical address field%d"
223 pr_debug("SSFDC_RO: logical address field%d"
226 "parity error(0x%04X)\n", j+1,
227 block_address);
228 } else {
229 ok = 1;
230 break;
231 }
232 }
233 }
234
235 if (!ok)
236 block_address = -2;
237
224 "parity error(0x%04X)\n", j+1,
225 block_address);
226 } else {
227 ok = 1;
228 break;
229 }
230 }
231 }
232
233 if (!ok)
234 block_address = -2;
235
238 DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n",
236 pr_debug("SSFDC_RO: get_logical_address() %d\n",
239 block_address);
240
241 return block_address;
242}
243
244/* Build the logic block map */
245static int build_logical_block_map(struct ssfdcr_record *ssfdc)
246{
247 unsigned long offset;
248 uint8_t oob_buf[OOB_SIZE];
249 int ret, block_address, phys_block;
250 struct mtd_info *mtd = ssfdc->mbd.mtd;
251
237 block_address);
238
239 return block_address;
240}
241
242/* Build the logic block map */
243static int build_logical_block_map(struct ssfdcr_record *ssfdc)
244{
245 unsigned long offset;
246 uint8_t oob_buf[OOB_SIZE];
247 int ret, block_address, phys_block;
248 struct mtd_info *mtd = ssfdc->mbd.mtd;
249
252 DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n",
250 pr_debug("SSFDC_RO: build_block_map() nblks=%d (%luK)\n",
253 ssfdc->map_len,
254 (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024);
255
256 /* Scan every physical block, skip CIS block */
257 for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len;
258 phys_block++) {
259 offset = (unsigned long)phys_block * ssfdc->erase_size;
260 if (mtd->block_isbad(mtd, offset))
261 continue; /* skip bad blocks */
262
263 ret = read_raw_oob(mtd, offset, oob_buf);
264 if (ret < 0) {
251 ssfdc->map_len,
252 (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024);
253
254 /* Scan every physical block, skip CIS block */
255 for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len;
256 phys_block++) {
257 offset = (unsigned long)phys_block * ssfdc->erase_size;
258 if (mtd->block_isbad(mtd, offset))
259 continue; /* skip bad blocks */
260
261 ret = read_raw_oob(mtd, offset, oob_buf);
262 if (ret < 0) {
265 DEBUG(MTD_DEBUG_LEVEL0,
266 "SSFDC_RO: mtd read_oob() failed at %lu\n",
263 pr_debug("SSFDC_RO: mtd read_oob() failed at %lu\n",
267 offset);
268 return -1;
269 }
270 block_address = get_logical_address(oob_buf);
271
272 /* Skip invalid addresses */
273 if (block_address >= 0 &&
274 block_address < MAX_LOGIC_BLK_PER_ZONE) {
275 int zone_index;
276
277 zone_index = phys_block / MAX_PHYS_BLK_PER_ZONE;
278 block_address += zone_index * MAX_LOGIC_BLK_PER_ZONE;
279 ssfdc->logic_block_map[block_address] =
280 (unsigned short)phys_block;
281
264 offset);
265 return -1;
266 }
267 block_address = get_logical_address(oob_buf);
268
269 /* Skip invalid addresses */
270 if (block_address >= 0 &&
271 block_address < MAX_LOGIC_BLK_PER_ZONE) {
272 int zone_index;
273
274 zone_index = phys_block / MAX_PHYS_BLK_PER_ZONE;
275 block_address += zone_index * MAX_LOGIC_BLK_PER_ZONE;
276 ssfdc->logic_block_map[block_address] =
277 (unsigned short)phys_block;
278
282 DEBUG(MTD_DEBUG_LEVEL2,
283 "SSFDC_RO: build_block_map() phys_block=%d,"
279 pr_debug("SSFDC_RO: build_block_map() phys_block=%d,"
284 "logic_block_addr=%d, zone=%d\n",
285 phys_block, block_address, zone_index);
286 }
287 }
288 return 0;
289}
290
291static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)

--- 19 unchanged lines hidden (view full) ---

311 ssfdc->mbd.devnum = -1;
312 ssfdc->mbd.tr = tr;
313 ssfdc->mbd.readonly = 1;
314
315 ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
316 ssfdc->erase_size = mtd->erasesize;
317 ssfdc->map_len = (u32)mtd->size / mtd->erasesize;
318
280 "logic_block_addr=%d, zone=%d\n",
281 phys_block, block_address, zone_index);
282 }
283 }
284 return 0;
285}
286
287static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)

--- 19 unchanged lines hidden (view full) ---

307 ssfdc->mbd.devnum = -1;
308 ssfdc->mbd.tr = tr;
309 ssfdc->mbd.readonly = 1;
310
311 ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
312 ssfdc->erase_size = mtd->erasesize;
313 ssfdc->map_len = (u32)mtd->size / mtd->erasesize;
314
319 DEBUG(MTD_DEBUG_LEVEL1,
320 "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
315 pr_debug("SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
321 ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
322 DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE));
323
324 /* Set geometry */
325 ssfdc->heads = 16;
326 ssfdc->sectors = 32;
327 get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
328 ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) /
329 ((long)ssfdc->sectors * (long)ssfdc->heads));
330
316 ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
317 DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE));
318
319 /* Set geometry */
320 ssfdc->heads = 16;
321 ssfdc->sectors = 32;
322 get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
323 ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) /
324 ((long)ssfdc->sectors * (long)ssfdc->heads));
325
331 DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
326 pr_debug("SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
332 ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,
333 (long)ssfdc->cylinders * (long)ssfdc->heads *
334 (long)ssfdc->sectors);
335
336 ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders *
337 (long)ssfdc->sectors;
338
339 /* Allocate logical block map */

--- 20 unchanged lines hidden (view full) ---

360 kfree(ssfdc->logic_block_map);
361 kfree(ssfdc);
362}
363
364static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)
365{
366 struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
367
327 ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,
328 (long)ssfdc->cylinders * (long)ssfdc->heads *
329 (long)ssfdc->sectors);
330
331 ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders *
332 (long)ssfdc->sectors;
333
334 /* Allocate logical block map */

--- 20 unchanged lines hidden (view full) ---

355 kfree(ssfdc->logic_block_map);
356 kfree(ssfdc);
357}
358
359static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)
360{
361 struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
362
368 DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);
363 pr_debug("SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);
369
370 del_mtd_blktrans_dev(dev);
371 kfree(ssfdc->logic_block_map);
372}
373
374static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
375 unsigned long logic_sect_no, char *buf)
376{
377 struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
378 int sectors_per_block, offset, block_address;
379
380 sectors_per_block = ssfdc->erase_size >> SECTOR_SHIFT;
381 offset = (int)(logic_sect_no % sectors_per_block);
382 block_address = (int)(logic_sect_no / sectors_per_block);
383
364
365 del_mtd_blktrans_dev(dev);
366 kfree(ssfdc->logic_block_map);
367}
368
369static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
370 unsigned long logic_sect_no, char *buf)
371{
372 struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
373 int sectors_per_block, offset, block_address;
374
375 sectors_per_block = ssfdc->erase_size >> SECTOR_SHIFT;
376 offset = (int)(logic_sect_no % sectors_per_block);
377 block_address = (int)(logic_sect_no / sectors_per_block);
378
384 DEBUG(MTD_DEBUG_LEVEL3,
385 "SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"
379 pr_debug("SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"
386 " block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
387 block_address);
388
389 if (block_address >= ssfdc->map_len)
390 BUG();
391
392 block_address = ssfdc->logic_block_map[block_address];
393
380 " block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
381 block_address);
382
383 if (block_address >= ssfdc->map_len)
384 BUG();
385
386 block_address = ssfdc->logic_block_map[block_address];
387
394 DEBUG(MTD_DEBUG_LEVEL3,
395 "SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",
388 pr_debug("SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",
396 block_address);
397
398 if (block_address < 0xffff) {
399 unsigned long sect_no;
400
401 sect_no = (unsigned long)block_address * sectors_per_block +
402 offset;
403
389 block_address);
390
391 if (block_address < 0xffff) {
392 unsigned long sect_no;
393
394 sect_no = (unsigned long)block_address * sectors_per_block +
395 offset;
396
404 DEBUG(MTD_DEBUG_LEVEL3,
405 "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",
397 pr_debug("SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",
406 sect_no);
407
408 if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0)
409 return -EIO;
410 } else {
411 memset(buf, 0xff, SECTOR_SIZE);
412 }
413
414 return 0;
415}
416
417static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
418{
419 struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
420
398 sect_no);
399
400 if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0)
401 return -EIO;
402 } else {
403 memset(buf, 0xff, SECTOR_SIZE);
404 }
405
406 return 0;
407}
408
409static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
410{
411 struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
412
421 DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",
413 pr_debug("SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",
422 ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);
423
424 geo->heads = ssfdc->heads;
425 geo->sectors = ssfdc->sectors;
426 geo->cylinders = ssfdc->cylinders;
427
428 return 0;
429}

--- 37 unchanged lines hidden ---
414 ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);
415
416 geo->heads = ssfdc->heads;
417 geo->sectors = ssfdc->sectors;
418 geo->cylinders = ssfdc->cylinders;
419
420 return 0;
421}

--- 37 unchanged lines hidden ---