📄 sddr09.c
字号:
} if (status & 0x40) US_DEBUGP(" Ready"); if (status & 0x20) US_DEBUGP(" Suspended"); if (status & 0x1) US_DEBUGP(" Error"); US_DEBUGP("\n"); return USB_STOR_TRANSPORT_GOOD;}#if 0/* * Reset Command: 12 bytes. * byte 0: opcode: EB */static intsddr09_reset(struct us_data *us) { unsigned char command[12] = { 0xeb, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return sddr09_send_scsi_command(us, command, sizeof(command));}#endifstatic struct nand_flash_dev *sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { struct nand_flash_dev *cardinfo; unsigned char deviceID[4]; char blurbtxt[256]; int result; US_DEBUGP("Reading capacity...\n"); result = sddr09_read_deviceID(us, deviceID); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("Result of read_deviceID is %d\n", result); printk("sddr09: could not read card info\n"); return 0; } sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X", deviceID[0], deviceID[1], deviceID[2], deviceID[3]); /* Byte 0 is the manufacturer */ sprintf(blurbtxt + strlen(blurbtxt), ": Manuf. %s", nand_flash_manufacturer(deviceID[0])); /* Byte 1 is the device type */ cardinfo = nand_find_id(deviceID[1]); if (cardinfo) { /* MB or MiB? It is neither. A 16 MB card has 17301504 raw bytes, of which 16384000 are usable for user data. */ sprintf(blurbtxt + strlen(blurbtxt), ", %d MB", 1<<(cardinfo->chipshift - 20)); } else { sprintf(blurbtxt + strlen(blurbtxt), ", type unrecognized"); } /* Byte 2 is code to signal availability of 128-bit ID */ if (deviceID[2] == 0xa5) { sprintf(blurbtxt + strlen(blurbtxt), ", 128-bit ID"); } /* Byte 3 announces the availability of another read ID command */ if (deviceID[3] == 0xc0) { sprintf(blurbtxt + strlen(blurbtxt), ", extra cmd"); } if (flags & SDDR09_WP) sprintf(blurbtxt + strlen(blurbtxt), ", WP"); printk("%s\n", blurbtxt); return cardinfo;}static intsddr09_read_map(struct us_data *us) { struct scatterlist *sg; struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; int numblocks, alloc_len, alloc_blocks; int i, j, result; unsigned char *ptr; unsigned int lba, lbact; if (!info->capacity) return -1; // read 64 (1<<6) bytes for every block // ( 1 << ( blockshift + pageshift ) bytes) // of capacity: // (1<<6)*capacity/(1<<(b+p)) = // ((1<<6)*capacity)>>(b+p) = // capacity>>(b+p-6) alloc_len = info->capacity >> (info->blockshift + info->pageshift - CONTROL_SHIFT); // Allocate a number of scatterlist structures according to // the number of 128k blocks in the alloc_len. Adding 128k-1 // and then dividing by 128k gives the correct number of blocks. // 128k = 1<<17 alloc_blocks = (alloc_len + (1<<17) - 1) >> 17; sg = kmalloc(alloc_blocks*sizeof(struct scatterlist), GFP_NOIO); if (sg == NULL) return 0; for (i=0; i<alloc_blocks; i++) { if (i<alloc_blocks-1) { sg[i].address = kmalloc( (1<<17), GFP_NOIO ); sg[i].page = NULL; sg[i].length = (1<<17); } else { sg[i].address = kmalloc(alloc_len, GFP_NOIO); sg[i].page = NULL; sg[i].length = alloc_len; } alloc_len -= sg[i].length; } for (i=0; i<alloc_blocks; i++) if (sg[i].address == NULL) { for (i=0; i<alloc_blocks; i++) if (sg[i].address != NULL) kfree(sg[i].address); kfree(sg); return 0; } numblocks = info->capacity >> (info->blockshift + info->pageshift); result = sddr09_read_control(us, 0, numblocks, (unsigned char *)sg, alloc_blocks); if (result != USB_STOR_TRANSPORT_GOOD) { for (i=0; i<alloc_blocks; i++) kfree(sg[i].address); kfree(sg); return -1; } kfree(info->lba_to_pba); kfree(info->pba_to_lba); info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { kfree(info->lba_to_pba); kfree(info->pba_to_lba); info->lba_to_pba = NULL; info->pba_to_lba = NULL; for (i=0; i<alloc_blocks; i++) kfree(sg[i].address); kfree(sg); return 0; } for (i = 0; i < numblocks; i++) info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF; ptr = sg[0].address; /* * Define lba-pba translation table */ // Each block is 64 bytes of control data, so block i is located in // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)#if 0 /* No translation */ for (i=0; i<numblocks; i++) { lba = i; info->pba_to_lba[i] = lba; info->lba_to_pba[lba] = i; } printk("sddr09: no translation today\n");#else for (i=0; i<numblocks; i++) { ptr = sg[i>>11].address + ((i&0x7ff)<<6); if (i == 0 || i == 1) { info->pba_to_lba[i] = UNUSABLE; continue; } /* special PBAs have control field 0^16 */ for (j = 0; j < 16; j++) if (ptr[j] != 0) goto nonz; info->pba_to_lba[i] = UNUSABLE; printk("sddr09: PBA %04X has no logical mapping\n", i); continue; nonz: /* unwritten PBAs have control field FF^16 */ for (j = 0; j < 16; j++) if (ptr[j] != 0xff) goto nonff; continue; nonff: /* normal PBAs start with six FFs */ if (j < 6) { printk("sddr09: PBA %04X has no logical mapping: " "reserved area = %02X%02X%02X%02X " "data status %02X block status %02X\n", i, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); info->pba_to_lba[i] = UNUSABLE; continue; } if ((ptr[6] >> 4) != 0x01) { printk("sddr09: PBA %04X has invalid address field " "%02X%02X/%02X%02X\n", i, ptr[6], ptr[7], ptr[11], ptr[12]); info->pba_to_lba[i] = UNUSABLE; continue; } /* check even parity */ if (parity[ptr[6] ^ ptr[7]]) { printk("sddr09: Bad parity in LBA for block %04X" " (%02X %02X)\n", i, ptr[6], ptr[7]); info->pba_to_lba[i] = UNUSABLE; continue; } lba = short_pack(ptr[7], ptr[6]); lba = (lba & 0x07FF) >> 1; /* * Every 1024 physical blocks ("zone"), the LBA numbers * go back to zero, but are within a higher block of LBA's. * Also, there is a maximum of 1000 LBA's per zone. * In other words, in PBA 1024-2047 you will find LBA 0-999 * which are really LBA 1000-1999. This allows for 24 bad * or special physical blocks per zone. */ if (lba >= 1000) { printk("sddr09: Bad LBA %04X for block %04X\n", lba, i); info->pba_to_lba[i] = UNDEF /* UNUSABLE */; continue; } lba += 1000*(i/0x400); if (lba<0x10 || (lba >= 0x3E0 && lba < 0x3EF)) US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); info->pba_to_lba[i] = lba; info->lba_to_pba[lba] = i; }#endif /* * Approximate capacity. This is not entirely correct yet, * since a zone with less than 1000 usable pages leads to * missing LBAs. Especially if it is the last zone, some * LBAs can be past capacity. */ lbact = 0; for (i = 0; i < numblocks; i += 1024) { int ct = 0; for (j = 0; j < 1024 && i+j < numblocks; j++) { if (info->pba_to_lba[i+j] != UNUSABLE) { if (ct >= 1000) info->pba_to_lba[i+j] = SPARE; else ct++; } } lbact += ct; } info->lbact = lbact; US_DEBUGP("Found %d LBA's\n", lbact); for (i=0; i<alloc_blocks; i++) kfree(sg[i].address); kfree(sg); return 0;}static voidsddr09_card_info_destructor(void *extra) { struct sddr09_card_info *info = (struct sddr09_card_info *)extra; if (!info) return; kfree(info->lba_to_pba); kfree(info->pba_to_lba);}static voidsddr09_init_card_info(struct us_data *us) { if (!us->extra) { us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO); if (us->extra) { memset(us->extra, 0, sizeof(struct sddr09_card_info)); us->extra_destructor = sddr09_card_info_destructor; } }}/* * It is unclear whether this does anything. * However, the request sense succeeds only after a reboot, * not if we do this a second time. */intsddr09_init(struct us_data *us) {#if 0 int result; unsigned char data[2]; printk("sddr09_init\n"); nand_init_ecc(); result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("sddr09_init: send_command fails\n"); return result; } US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); // get 07 02 result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("sddr09_init: 2nd send_command fails\n"); return result; } US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); // get 07 00#if 1 result = sddr09_request_sense(us, data, sizeof(data)); if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) { int j; for (j=0; j<sizeof(data); j++) printk(" %02X", data[j]); printk("\n"); // get 70 00 00 00 00 00 00 * 00 00 00 00 00 00 // 70: current command // sense key 0, sense code 0, extd sense code 0 // additional transfer length * = sizeof(data) - 7 }#endif#endif return USB_STOR_TRANSPORT_GOOD; /* not result */}/* * Transport for the Sandisk SDDR-09 */int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us){ static unsigned char sense = 0; static unsigned char havefakesense = 0; int result, i; unsigned char *ptr; unsigned long capacity; unsigned int page, pages; char string[64]; struct sddr09_card_info *info; unsigned char inquiry_response[36] = { 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 }; unsigned char mode_page_01[16] = { 0x0F, 0x00, 0, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; info = (struct sddr09_card_info *)us->extra; if (!info) { nand_init_ecc(); sddr09_init_card_info(us); info = (struct sddr09_card_info *)us->extra; if (!info) return USB_STOR_TRANSPORT_ERROR; } ptr = (unsigned char *)srb->request_buffer; if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) { /* for a faked command, we have to follow with a faked sense */ memset(ptr, 0, srb->request_bufflen); if (srb->request_bufflen > 7) { ptr[0] = 0x70; ptr[2] = sense; ptr[7] = srb->request_bufflen - 7; } sense = havefakesense = 0; return USB_STOR_TRANSPORT_GOOD; } sense = 0; havefakesense = 1; /* Dummy up a response for INQUIRY since SDDR09 doesn't respond to INQUIRY commands */ if (srb->cmnd[0] == INQUIRY) { memset(inquiry_response+8, 0, 28); fill_inquiry_response(us, inquiry_response, 36); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == READ_CAPACITY) { struct nand_flash_dev *cardinfo; sddr09_get_wp(us, info); /* read WP bit */ cardinfo = sddr09_get_cardinfo(us, info->flags); if (!cardinfo) return USB_STOR_TRANSPORT_FAILED; info->capacity = (1 << cardinfo->chipshift); info->pageshift = cardinfo->pageshift; info->pagesize = (1 << info->pageshift); info->blockshift = cardinfo->blockshift; info->blocksize = (1 << info->blockshift); info->blockmask = info->blocksize - 1; // map initialization, must follow get_cardinfo() sddr09_read_map(us); // Report capacity capacity = (info->lbact << info->blockshift) - 1; ptr[0] = MSB_of(capacity>>16); ptr[1] = LSB_of(capacity>>16); ptr[2] = MSB_of(capacity&0xFFFF); ptr[3] = LSB_of(capacity&0xFFFF); // Report page size ptr[4] = MSB_of(info->pagesize>>16); ptr[5] = LSB_of(info->pagesize>>16); ptr[6] = MSB_of(info->pagesize&0xFFFF); ptr[7] = LSB_of(info->pagesize&0xFFFF); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == MODE_SENSE) { // Read-write error recovery page: there needs to // be a check for write-protect here if ( (srb->cmnd[2] & 0x3F) == 0x01 ) { US_DEBUGP( "SDDR09: Dummy up request for mode page 1\n"); if (ptr == NULL || srb->request_bufflen<sizeof(mode_page_01)) return USB_STOR_TRANSPORT_ERROR; mode_page_01[0] = sizeof(mode_page_01) - 1; mode_page_01[2] = (info->flags & SDDR09_WP) ? 0x80 : 0; memcpy(ptr, mode_page_01, sizeof(mode_page_01)); return USB_STOR_TRANSPORT_GOOD; } else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) { US_DEBUGP("SDDR09: Dummy up request for " "all mode pages\n"); if (ptr == NULL || srb->request_bufflen<sizeof(mode_page_01)) return USB_STOR_TRANSPORT_ERROR; memcpy(ptr, mode_page_01, sizeof(mode_page_01)); return USB_STOR_TRANSPORT_GOOD; } return USB_STOR_TRANSPORT_ERROR; } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { US_DEBUGP( "SDDR09: %s medium removal. Not that I can do" " anything about it...\n", (srb->cmnd[4]&0x03) ? "Prevent" : "Allow"); return USB_STOR_TRANSPORT_GOOD; } havefakesense = 0; if (srb->cmnd[0] == READ_10) { page = short_pack(srb->cmnd[3], srb->cmnd[2]); page <<= 16; page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); US_DEBUGP("READ_10: read page %d pagect %d\n", page, pages); return sddr09_read_data(us, page, pages, ptr, srb->use_sg); } if (srb->cmnd[0] == WRITE_10) { page = short_pack(srb->cmnd[3], srb->cmnd[2]); page <<= 16; page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); US_DEBUGP("WRITE_10: write page %d pagect %d\n", page, pages); return sddr09_write_data(us, page, pages, ptr, srb->use_sg); } // Pass TEST_UNIT_READY and REQUEST_SENSE through if (srb->cmnd[0] != TEST_UNIT_READY && srb->cmnd[0] != REQUEST_SENSE) { havefakesense = 1; return USB_STOR_TRANSPORT_ERROR; } for (; srb->cmd_len<12; srb->cmd_len++) srb->cmnd[srb->cmd_len] = 0; srb->cmnd[1] = 0x20; string[0] = 0; for (i=0; i<12; i++) sprintf(string+strlen(string), "%02X ", srb->cmnd[i]); US_DEBUGP("SDDR09: Send control for command %s\n", string); result = sddr09_send_scsi_command(us, srb->cmnd, 12); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("sddr09_transport: sddr09_send_scsi_command " "returns %d\n", result); return result; } if (srb->request_bufflen == 0) return USB_STOR_TRANSPORT_GOOD; if (srb->sc_data_direction == SCSI_DATA_WRITE || srb->sc_data_direction == SCSI_DATA_READ) { US_DEBUGP("SDDR09: %s %d bytes\n", (srb->sc_data_direction == SCSI_DATA_WRITE) ? "sending" : "receiving", srb->request_bufflen); result = sddr09_bulk_transport(us, srb->sc_data_direction, srb->request_buffer, srb->request_bufflen, srb->use_sg); return result; } return USB_STOR_TRANSPORT_GOOD;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -