📄 isd200.c
字号:
* 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 (info->drive.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*)info->drive.model; dest = (__u16*)info->InquiryData.VendorId; for (i=0;i<4;i++) dest[i] = be16_to_cpu(src[i]); src = (__u16*)(info->drive.model+8); dest = (__u16*)info->InquiryData.ProductId; for (i=0;i<8;i++) dest[i] = be16_to_cpu(src[i]); src = (__u16*)info->drive.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 (info->drive.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 */ if (us->extra != NULL) { kfree(us->extra); us->extra = NULL; us->extra_destructor = NULL; } } } US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus); return(retStatus);}/************************************************************************** * isd200_data_copy * * Copy data into the srb request buffer. Use scatter gather if required. * * RETURNS: * void */ void isd200_data_copy(Scsi_Cmnd *srb, char * src, int length){ unsigned int len = length; struct scatterlist *sg; if (srb->use_sg) { int i; unsigned int total = 0; /* Add up the sizes of all the sg segments */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) total += sg[i].length; if (length > total) len = total; total = 0; /* Copy data into sg buffer(s) */ for (i = 0; i < srb->use_sg; i++) { if ((len > total) && (len > 0)) { /* transfer the lesser of the next buffer or the * remaining data */ if (len - total >= sg[i].length) { memcpy(sg[i].address, src + total, sg[i].length); total += sg[i].length; } else { memcpy(sg[i].address, src + total, len - total); total = len; } } else break; } } else { /* Make sure length does not exceed buffer length */ if (length > srb->request_bufflen) len = srb->request_bufflen; if (len > 0) memcpy(srb->request_buffer, src, len); }}/************************************************************************** * 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 */ 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; 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"); if (srb->request_bufflen > sizeof(struct inquiry_data)) srb->request_bufflen = sizeof(struct inquiry_data); /* copy InquiryData */ isd200_data_copy(srb, (char *) &info->InquiryData, srb->request_bufflen); srb->result = GOOD; sendToTransport = FALSE; break; case MODE_SENSE: US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n"); /* Initialize the return buffer */ isd200_data_copy(srb, (char *) &senseData, 8); 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 = WIN_GETMEDIASTATUS; srb->request_bufflen = 0; } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = GOOD; sendToTransport = FALSE; } break; case TEST_UNIT_READY: US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n"); /* Initialize the return buffer */ isd200_data_copy(srb, (char *) &senseData, 8); 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 = WIN_GETMEDIASTATUS; srb->request_bufflen = 0; } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = GOOD; sendToTransport = FALSE; } break; case READ_CAPACITY: { unsigned long capacity; struct read_capacity_data readCapacityData; US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); if (info->drive.capability & CAPABILITY_LBA ) { capacity = info->drive.lba_capacity - 1; } else { capacity = (info->drive.heads * info->drive.cyls * info->drive.sectors) - 1; } readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); readCapacityData.BytesPerBlock = cpu_to_be32(0x200); if (srb->request_bufflen > sizeof(struct read_capacity_data)) srb->request_bufflen = sizeof(struct read_capacity_data); isd200_data_copy(srb, (char *) &readCapacityData, srb->request_bufflen); srb->result = 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 (info->drive.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 % info->drive.sectors) + 1); cylinder = (unsigned short)(lba / (info->drive.sectors * info->drive.heads)); head = (unsigned char)((lba / info->drive.sectors) % info->drive.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 (info->drive.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 % info->drive.sectors) + 1); cylinder = (unsigned short)(lba / (info->drive.sectors * info->drive.heads)); head = (unsigned char)((lba / info->drive.sectors) % info->drive.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 = 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]); /* Initialize the return buffer */ isd200_data_copy(srb, (char *) &senseData, 8); 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 = WIN_MEDIAEJECT; } 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 = WIN_GETMEDIASTATUS; srb->request_bufflen = 0; } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = 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_init_info * * Allocates (if necessary) and initializes the driver structure. * * RETURNS: * ISD status code */ int isd200_init_info(struct us_data *us){ int retStatus = ISD200_GOOD; if (!us->extra) { us->extra = (void *) kmalloc(sizeof(struct isd200_info), GFP_KERNEL); if (!us->extra) { US_DEBUGP("ERROR - kmalloc failure\n"); retStatus = ISD200_ERROR; } } if (retStatus == ISD200_GOOD) { memset(us->extra, 0, sizeof(struct isd200_info)); } 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 */ 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 + -