📄 isd200.c
字号:
info->ConfigData.ATAConfig &= 0x3f; info->ConfigData.ATAConfig |= (isslave<<6); retStatus = isd200_write_config(us); } } US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus); return(retStatus);}/************************************************************************** * isd200_get_inquiry_data * * Get inquiry data * * RETURNS: * ISD status code */static int isd200_get_inquiry_data( struct us_data *us ){ struct isd200_info *info = (struct isd200_info *)us->extra; int retStatus = ISD200_GOOD; struct hd_driveid *id = info->id; US_DEBUGP("Entering isd200_get_inquiry_data\n"); /* set default to Master */ info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD; /* attempt to manually enumerate this device */ retStatus = isd200_manual_enum(us); if (retStatus == ISD200_GOOD) { int transferStatus; /* check for an ATA device */ if (info->DeviceFlags & DF_ATA_DEVICE) { /* this must be an ATA device */ /* perform an ATA Command Identify */ transferStatus = isd200_action( us, ACTION_IDENTIFY, id, sizeof(struct hd_driveid) ); if (transferStatus != ISD200_TRANSPORT_GOOD) { /* Error issuing ATA Command Identify */ US_DEBUGP(" Error issuing ATA Command Identify\n"); retStatus = ISD200_ERROR; } else { /* ATA Command Identify successful */ int i; __u16 *src, *dest; ide_fix_driveid(id); US_DEBUGP(" Identify Data Structure:\n"); US_DEBUGP(" config = 0x%x\n", id->config); US_DEBUGP(" cyls = 0x%x\n", id->cyls); US_DEBUGP(" heads = 0x%x\n", id->heads); US_DEBUGP(" track_bytes = 0x%x\n", id->track_bytes); US_DEBUGP(" sector_bytes = 0x%x\n", id->sector_bytes); US_DEBUGP(" sectors = 0x%x\n", id->sectors); US_DEBUGP(" serial_no[0] = 0x%x\n", id->serial_no[0]); US_DEBUGP(" buf_type = 0x%x\n", id->buf_type); US_DEBUGP(" buf_size = 0x%x\n", id->buf_size); US_DEBUGP(" ecc_bytes = 0x%x\n", id->ecc_bytes); US_DEBUGP(" fw_rev[0] = 0x%x\n", id->fw_rev[0]); US_DEBUGP(" model[0] = 0x%x\n", id->model[0]); US_DEBUGP(" max_multsect = 0x%x\n", id->max_multsect); US_DEBUGP(" dword_io = 0x%x\n", id->dword_io); US_DEBUGP(" capability = 0x%x\n", id->capability); US_DEBUGP(" tPIO = 0x%x\n", id->tPIO); US_DEBUGP(" tDMA = 0x%x\n", id->tDMA); US_DEBUGP(" field_valid = 0x%x\n", id->field_valid); US_DEBUGP(" cur_cyls = 0x%x\n", id->cur_cyls); US_DEBUGP(" cur_heads = 0x%x\n", id->cur_heads); US_DEBUGP(" cur_sectors = 0x%x\n", id->cur_sectors); US_DEBUGP(" cur_capacity = 0x%x\n", (id->cur_capacity1 << 16) + id->cur_capacity0 ); US_DEBUGP(" multsect = 0x%x\n", id->multsect); US_DEBUGP(" lba_capacity = 0x%x\n", id->lba_capacity); US_DEBUGP(" command_set_1 = 0x%x\n", id->command_set_1); US_DEBUGP(" command_set_2 = 0x%x\n", id->command_set_2); memset(&info->InquiryData, 0, sizeof(info->InquiryData)); /* Standard IDE interface only supports disks */ info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE; /* Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us * in Linux. */ info->InquiryData.Versions = 0x2; /* The length must be at least 36 (5 + 31) */ info->InquiryData.AdditionalLength = 0x1F; if (id->command_set_1 & COMMANDSET_MEDIA_STATUS) { /* set the removable bit */ info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; info->DeviceFlags |= DF_REMOVABLE_MEDIA; } /* Fill in vendor identification fields */ src = (__u16*)id->model; dest = (__u16*)info->InquiryData.VendorId; for (i=0;i<4;i++) dest[i] = be16_to_cpu(src[i]); src = (__u16*)(id->model+8); dest = (__u16*)info->InquiryData.ProductId; for (i=0;i<8;i++) dest[i] = be16_to_cpu(src[i]); src = (__u16*)id->fw_rev; dest = (__u16*)info->InquiryData.ProductRevisionLevel; for (i=0;i<2;i++) dest[i] = be16_to_cpu(src[i]); /* determine if it supports Media Status Notification */ if (id->command_set_2 & COMMANDSET_MEDIA_STATUS) { US_DEBUGP(" Device supports Media Status Notification\n"); /* Indicate that it is enabled, even though it is not * This allows the lock/unlock of the media to work * correctly. */ info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED; } else info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED; } } else { /* * this must be an ATAPI device * use an ATAPI protocol (Transparent SCSI) */ us->protocol_name = "Transparent SCSI"; us->proto_handler = usb_stor_transparent_scsi_command; US_DEBUGP("Protocol changed to: %s\n", us->protocol_name); /* Free driver structure */ us->extra_destructor(info); us->extra = NULL; us->extra_destructor = NULL; } } US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus); return(retStatus);}/************************************************************************** * isd200_scsi_to_ata * * Translate SCSI commands to ATA commands. * * RETURNS: * TRUE if the command needs to be sent to the transport layer * FALSE otherwise */static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, union ata_cdb * ataCdb){ struct isd200_info *info = (struct isd200_info *)us->extra; struct hd_driveid *id = info->id; int sendToTransport = TRUE; unsigned char sectnum, head; unsigned short cylinder; unsigned long lba; unsigned long blockCount; unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; memset(ataCdb, 0, sizeof(union ata_cdb)); /* SCSI Command */ switch (srb->cmnd[0]) { case INQUIRY: US_DEBUGP(" ATA OUT - INQUIRY\n"); /* copy InquiryData */ usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, sizeof(info->InquiryData), srb); srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; break; case MODE_SENSE: US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n"); /* Initialize the return buffer */ usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb); if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) { ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; case TEST_UNIT_READY: US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n"); if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) { ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; case READ_CAPACITY: { unsigned long capacity; struct read_capacity_data readCapacityData; US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); if (id->capability & CAPABILITY_LBA ) { capacity = id->lba_capacity - 1; } else { capacity = (id->heads * id->cyls * id->sectors) - 1; } readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); readCapacityData.BytesPerBlock = cpu_to_be32(0x200); usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, sizeof(readCapacityData), srb); srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; case READ_10: US_DEBUGP(" ATA OUT - SCSIOP_READ\n"); lba = *(unsigned long *)&srb->cmnd[2]; lba = cpu_to_be32(lba); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; if (id->capability & CAPABILITY_LBA) { sectnum = (unsigned char)(lba); cylinder = (unsigned short)(lba>>8); head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); } else { sectnum = (unsigned char)((lba % id->sectors) + 1); cylinder = (unsigned short)(lba / (id->sectors * id->heads)); head = (unsigned char)((lba / id->sectors) % id->heads); } ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_SECTOR_COUNT | REG_SECTOR_NUMBER | REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; ataCdb->write.SectorNumberByte = sectnum; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); ataCdb->write.CylinderLowByte = (unsigned char)cylinder; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); ataCdb->write.CommandByte = WIN_READ; break; case WRITE_10: US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n"); lba = *(unsigned long *)&srb->cmnd[2]; lba = cpu_to_be32(lba); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; if (id->capability & CAPABILITY_LBA) { sectnum = (unsigned char)(lba); cylinder = (unsigned short)(lba>>8); head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); } else { sectnum = (unsigned char)((lba % id->sectors) + 1); cylinder = (unsigned short)(lba / (id->sectors * id->heads)); head = (unsigned char)((lba / id->sectors) % id->heads); } ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_SECTOR_COUNT | REG_SECTOR_NUMBER | REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_DEVICE_HEAD | REG_COMMAND; ataCdb->write.SectorCountByte = (unsigned char)blockCount; ataCdb->write.SectorNumberByte = sectnum; ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); ataCdb->write.CylinderLowByte = (unsigned char)cylinder; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); ataCdb->write.CommandByte = WIN_WRITE; break; case ALLOW_MEDIUM_REMOVAL: US_DEBUGP(" ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); if (info->DeviceFlags & DF_REMOVABLE_MEDIA) { US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK; srb->request_bufflen = 0; } else { US_DEBUGP(" Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; case START_STOP: US_DEBUGP(" ATA OUT - SCSIOP_START_STOP_UNIT\n"); US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); if ((srb->cmnd[4] & 0x3) == 0x2) { US_DEBUGP(" Media Eject\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 0; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; } else if ((srb->cmnd[4] & 0x3) == 0x1) { US_DEBUGP(" Get Media Status\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; srb->request_bufflen = 0; } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; default: US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); srb->result = DID_ERROR << 16; sendToTransport = FALSE; break; } return(sendToTransport);}/************************************************************************** * isd200_free_info * * Frees the driver structure. */static void isd200_free_info_ptrs(void *info_){ struct isd200_info *info = (struct isd200_info *) info_; if (info) { kfree(info->id); kfree(info->RegsBuf); }}/************************************************************************** * isd200_init_info * * Allocates (if necessary) and initializes the driver structure. * * RETURNS: * ISD status code */static int isd200_init_info(struct us_data *us){ int retStatus = ISD200_GOOD; struct isd200_info *info; info = (struct isd200_info *) kmalloc(sizeof(struct isd200_info), GFP_KERNEL); if (!info) retStatus = ISD200_ERROR; else { memset(info, 0, sizeof(struct isd200_info)); info->id = (struct hd_driveid *) kmalloc(sizeof(struct hd_driveid), GFP_KERNEL); info->RegsBuf = (unsigned char *) kmalloc(sizeof(info->ATARegs), GFP_KERNEL); if (!info->id || !info->RegsBuf) { isd200_free_info_ptrs(info); kfree(info); retStatus = ISD200_ERROR; } else memset(info->id, 0, sizeof(struct hd_driveid)); } if (retStatus == ISD200_GOOD) { us->extra = info; us->extra_destructor = isd200_free_info_ptrs; } else US_DEBUGP("ERROR - kmalloc failure\n"); return(retStatus);}/************************************************************************** * Initialization for the ISD200 */int isd200_Initialization(struct us_data *us){ US_DEBUGP("ISD200 Initialization...\n"); /* Initialize ISD200 info struct */ if (isd200_init_info(us) == ISD200_ERROR) { US_DEBUGP("ERROR Initializing ISD200 Info struct\n"); } else { /* Get device specific data */ if (isd200_get_inquiry_data(us) != ISD200_GOOD) US_DEBUGP("ISD200 Initialization Failure\n"); else US_DEBUGP("ISD200 Initialization complete\n"); } return 0;}/************************************************************************** * Protocol and Transport for the ISD200 ASIC * * This protocol and transport are for ATA devices connected to an ISD200 * ASIC. An ATAPI device that is conected as a slave device will be * detected in the driver initialization function and the protocol will * be changed to an ATAPI protocol (Transparent SCSI). * */void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us){ int sendToTransport = TRUE; union ata_cdb ataCdb; /* Make sure driver was initialized */ if (us->extra == NULL) US_DEBUGP("ERROR Driver not initialized\n"); /* Convert command */ srb->resid = 0; sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); /* send the command to the transport layer */ if (sendToTransport) isd200_invoke_transport(us, srb, &ataCdb);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -