📄 cmd_ide.c
字号:
static uchar led_buffer = 0; /* Buffer for current LED status */static void ide_led (uchar led, uchar status){ uchar *led_port = LED_PORT; if (status) { /* switch LED on */ led_buffer |= led; } else { /* switch LED off */ led_buffer &= ~led; } *led_port = led_buffer;}#endif /* CONFIG_IDE_LED *//* ------------------------------------------------------------------------- */#ifdef CONFIG_ATAPI/**************************************************************************** * ATAPI Support */#undef ATAPI_DEBUG#ifdef ATAPI_DEBUG#define AT_PRINTF(fmt,args...) printf (fmt ,##args)#else#define AT_PRINTF(fmt,args...)#endif#if defined(__PPC__) || defined(CONFIG_PXA_PCMCIA)/* since ATAPI may use commands with not 4 bytes alligned length * we have our own transfer functions, 2 bytes alligned */static voidoutput_data_shorts(int dev, ushort *sect_buf, int shorts){#ifndef CONFIG_HMI10 ushort *dbuf; volatile ushort *pbuf; pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); dbuf = (ushort *)sect_buf; PRINTF("in output data shorts base for read is %lx\n", (unsigned long) pbuf); while (shorts--) { EIEIO; *pbuf = *dbuf++; }#else /* CONFIG_HMI10 */ uchar *dbuf; volatile uchar *pbuf_even; volatile uchar *pbuf_odd; pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN); pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD); while (shorts--) { EIEIO; *pbuf_even = *dbuf++; EIEIO; *pbuf_odd = *dbuf++; }#endif /* CONFIG_HMI10 */}static voidinput_data_shorts(int dev, ushort *sect_buf, int shorts){#ifndef CONFIG_HMI10 ushort *dbuf; volatile ushort *pbuf; pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); dbuf = (ushort *)sect_buf; PRINTF("in input data shorts base for read is %lx\n", (unsigned long) pbuf); while (shorts--) { EIEIO; *dbuf++ = *pbuf; }#else /* CONFIG_HMI10 */ uchar *dbuf; volatile uchar *pbuf_even; volatile uchar *pbuf_odd; pbuf_even = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_EVEN); pbuf_odd = (uchar *)(ATA_CURR_BASE(dev)+ATA_DATA_ODD); while (shorts--) { EIEIO; *dbuf++ = *pbuf_even; EIEIO; *dbuf++ = *pbuf_odd; }#endif /* CONFIG_HMI10 */}#else /* ! __PPC__ */static voidoutput_data_shorts(int dev, ushort *sect_buf, int shorts){ outsw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts);}static voidinput_data_shorts(int dev, ushort *sect_buf, int shorts){ insw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts);}#endif /* __PPC__ *//* * Wait until (Status & mask) == res, or timeout (in ms) * Return last status * This is used since some ATAPI CD ROMs clears their Busy Bit first * and then they set their DRQ Bit */static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res){ ulong delay = 10 * t; /* poll every 100 us */ uchar c; c = ide_inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */ while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) { /* break if error occurs (doesn't make sense to wait more) */ if((c & ATA_STAT_ERR)==ATA_STAT_ERR) break; udelay (100); if (delay-- == 0) { break; } } return (c);}/* * issue an atapi command */unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen){ unsigned char c,err,mask,res; int n; ide_led (DEVICE_LED(device), 1); /* LED on */ /* Select device */ mask = ATA_STAT_BUSY|ATA_STAT_DRQ; res = 0;#ifdef CONFIG_AMIGAONEG3SE# warning THF: Removed LBA mode ???#endif ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & mask) != res) { printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c); err=0xFF; goto AI_OUT; } /* write taskfile */ ide_outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */ ide_outb (device, ATA_SECT_CNT, 0); ide_outb (device, ATA_SECT_NUM, 0); ide_outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF)); ide_outb (device, ATA_CYL_HIGH, (unsigned char)((buflen>>8) & 0xFF));#ifdef CONFIG_AMIGAONEG3SE# warning THF: Removed LBA mode ???#endif ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); ide_outb (device, ATA_COMMAND, ATAPI_CMD_PACKET); udelay (50); mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR; res = ATA_STAT_DRQ; c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */ printf ("ATTAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c); err=0xFF; goto AI_OUT; } output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */ /* ATAPI Command written wait for completition */ udelay (5000); /* device must set bsy */ mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR; /* if no data wait for DRQ = 0 BSY = 0 * if data wait for DRQ = 1 BSY = 0 */ res=0; if(buflen) res = ATA_STAT_DRQ; c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & mask) != res ) { if (c & ATA_STAT_ERR) { err=(ide_inb(device,ATA_ERROR_REG))>>4; AT_PRINTF("atapi_issue 1 returned sense key %X status %02X\n",err,c); } else { printf ("ATTAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", ccb[0],c); err=0xFF; } goto AI_OUT; } n=ide_inb(device, ATA_CYL_HIGH); n<<=8; n+=ide_inb(device, ATA_CYL_LOW); if(n>buflen) { printf("ERROR, transfer bytes %d requested only %d\n",n,buflen); err=0xff; goto AI_OUT; } if((n==0)&&(buflen<0)) { printf("ERROR, transfer bytes %d requested %d\n",n,buflen); err=0xff; goto AI_OUT; } if(n!=buflen) { AT_PRINTF("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen); } if(n!=0) { /* data transfer */ AT_PRINTF("ATAPI_ISSUE: %d Bytes to transfer\n",n); /* we transfer shorts */ n>>=1; /* ok now decide if it is an in or output */ if ((ide_inb(device, ATA_SECT_CNT)&0x02)==0) { AT_PRINTF("Write to device\n"); output_data_shorts(device,(unsigned short *)buffer,n); } else { AT_PRINTF("Read from device @ %p shorts %d\n",buffer,n); input_data_shorts(device,(unsigned short *)buffer,n); } } udelay(5000); /* seems that some CD ROMs need this... */ mask = ATA_STAT_BUSY|ATA_STAT_ERR; res=0; c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { err=(ide_inb(device,ATA_ERROR_REG) >> 4); AT_PRINTF("atapi_issue 2 returned sense key %X status %X\n",err,c); } else { err = 0; }AI_OUT: ide_led (DEVICE_LED(device), 0); /* LED off */ return (err);}/* * sending the command to atapi_issue. If an status other than good * returns, an request_sense will be issued */#define ATAPI_DRIVE_NOT_READY 100#define ATAPI_UNIT_ATTN 10unsigned char atapi_issue_autoreq (int device, unsigned char* ccb, int ccblen, unsigned char *buffer, int buflen){ unsigned char sense_data[18],sense_ccb[12]; unsigned char res,key,asc,ascq; int notready,unitattn;#ifdef CONFIG_AMIGAONEG3SE char *s; unsigned int timeout, retrycnt; s = getenv("ide_cd_timeout"); timeout = s ? (simple_strtol(s, NULL, 10)*1000000)/5 : 0; retrycnt = 0;#endif unitattn=ATAPI_UNIT_ATTN; notready=ATAPI_DRIVE_NOT_READY;retry: res= atapi_issue(device,ccb,ccblen,buffer,buflen); if (res==0) return (0); /* Ok */ if (res==0xFF) return (0xFF); /* error */ AT_PRINTF("(auto_req)atapi_issue returned sense key %X\n",res); memset(sense_ccb,0,sizeof(sense_ccb)); memset(sense_data,0,sizeof(sense_data)); sense_ccb[0]=ATAPI_CMD_REQ_SENSE; sense_ccb[4]=18; /* allocation Length */ res=atapi_issue(device,sense_ccb,12,sense_data,18); key=(sense_data[2]&0xF); asc=(sense_data[12]); ascq=(sense_data[13]); AT_PRINTF("ATAPI_CMD_REQ_SENSE returned %x\n",res); AT_PRINTF(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n", sense_data[0], key, asc, ascq); if((key==0)) return 0; /* ok device ready */ if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */ if(unitattn-->0) { udelay(200*1000); goto retry; } printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN); goto error; } if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */ if (notready-->0) { udelay(200*1000); goto retry; } printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY); goto error; } if(asc==0x3a) { AT_PRINTF("Media not present\n"); goto error; }#ifdef CONFIG_AMIGAONEG3SE if ((sense_data[2]&0xF)==0x0B) { AT_PRINTF("ABORTED COMMAND...retry\n"); if (retrycnt++ < 4) goto retry; return (0xFF); } if ((sense_data[2]&0xf) == 0x02 && sense_data[12] == 0x04 && sense_data[13] == 0x01 ) { AT_PRINTF("Waiting for unit to become active\n"); udelay(timeout); if (retrycnt++ < 4) goto retry; return 0xFF; }#endif /* CONFIG_AMIGAONEG3SE */ printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq);error: AT_PRINTF ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq); return (0xFF);}static void atapi_inquiry(block_dev_desc_t * dev_desc){ unsigned char ccb[12]; /* Command descriptor block */ unsigned char iobuf[64]; /* temp buf */ unsigned char c; int device; device=dev_desc->dev; dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */ dev_desc->block_read=atapi_read; memset(ccb,0,sizeof(ccb)); memset(iobuf,0,sizeof(iobuf)); ccb[0]=ATAPI_CMD_INQUIRY; ccb[4]=40; /* allocation Legnth */ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40); AT_PRINTF("ATAPI_CMD_INQUIRY returned %x\n",c); if (c!=0) return; /* copy device ident strings */ ident_cpy(dev_desc->vendor,&iobuf[8],8); ident_cpy(dev_desc->product,&iobuf[16],16); ident_cpy(dev_desc->revision,&iobuf[32],5); dev_desc->lun=0; dev_desc->lba=0; dev_desc->blksz=0; dev_desc->type=iobuf[0] & 0x1f; if ((iobuf[1]&0x80)==0x80) dev_desc->removable = 1; else dev_desc->removable = 0; memset(ccb,0,sizeof(ccb)); memset(iobuf,0,sizeof(iobuf)); ccb[0]=ATAPI_CMD_START_STOP; ccb[4]=0x03; /* start */ c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0); AT_PRINTF("ATAPI_CMD_START_STOP returned %x\n",c); if (c!=0) return; memset(ccb,0,sizeof(ccb)); memset(iobuf,0,sizeof(iobuf)); c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0); AT_PRINTF("ATAPI_CMD_UNIT_TEST_READY returned %x\n",c); if (c!=0) return; memset(ccb,0,sizeof(ccb)); memset(iobuf,0,sizeof(iobuf)); ccb[0]=ATAPI_CMD_READ_CAP; c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,8); AT_PRINTF("ATAPI_CMD_READ_CAP returned %x\n",c); if (c!=0) return; AT_PRINTF("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n", iobuf[0],iobuf[1],iobuf[2],iobuf[3], iobuf[4],iobuf[5],iobuf[6],iobuf[7]); dev_desc->lba =((unsigned long)iobuf[0]<<24) + ((unsigned long)iobuf[1]<<16) + ((unsigned long)iobuf[2]<< 8) + ((unsigned long)iobuf[3]); dev_desc->blksz=((unsigned long)iobuf[4]<<24) + ((unsigned long)iobuf[5]<<16) + ((unsigned long)iobuf[6]<< 8) + ((unsigned long)iobuf[7]);#ifdef CONFIG_LBA48 dev_desc->lba48 = 0; /* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */#endif return;}/* * atapi_read: * we transfer only one block per command, since the multiple DRQ per * command is not yet implemented */#define ATAPI_READ_MAX_BYTES 2048 /* we read max 2kbytes */#define ATAPI_READ_BLOCK_SIZE 2048 /* assuming CD part */#define ATAPI_READ_MAX_BLOCK ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE /* max blocks */ulong atapi_read (int device, lbaint_t blknr, ulong blkcnt, ulong *buffer){ ulong n = 0; unsigned char ccb[12]; /* Command descriptor block */ ulong cnt; AT_PRINTF("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n", device, blknr, blkcnt, (ulong)buffer); do { if (blkcnt>ATAPI_READ_MAX_BLOCK) { cnt=ATAPI_READ_MAX_BLOCK; } else { cnt=blkcnt; } ccb[0]=ATAPI_CMD_READ_12; ccb[1]=0; /* reserved */ ccb[2]=(unsigned char) (blknr>>24) & 0xFF; /* MSB Block */ ccb[3]=(unsigned char) (blknr>>16) & 0xFF; /* */ ccb[4]=(unsigned char) (blknr>> 8) & 0xFF; ccb[5]=(unsigned char) blknr & 0xFF; /* LSB Block */ ccb[6]=(unsigned char) (cnt >>24) & 0xFF; /* MSB Block count */ ccb[7]=(unsigned char) (cnt >>16) & 0xFF; ccb[8]=(unsigned char) (cnt >> 8) & 0xFF; ccb[9]=(unsigned char) cnt & 0xFF; /* LSB Block */ ccb[10]=0; /* reserved */ ccb[11]=0; /* reserved */ if (atapi_issue_autoreq(device,ccb,12, (unsigned char *)buffer, cnt*ATAPI_READ_BLOCK_SIZE) == 0xFF) { return (n); } n+=cnt; blkcnt-=cnt; blknr+=cnt; buffer+=cnt*(ATAPI_READ_BLOCK_SIZE/4); /* ulong blocksize in ulong */ } while (blkcnt > 0); return (n);}/* ------------------------------------------------------------------------- */#endif /* CONFIG_ATAPI */U_BOOT_CMD( ide, 5, 1, do_ide, "ide - IDE sub-system\n", "reset - reset IDE controller\n" "ide info - show available IDE devices\n" "ide device [dev] - show or set current device\n" "ide part [dev] - print partition table of one or all IDE devices\n" "ide read addr blk# cnt\n" "ide write addr blk# cnt - read/write `cnt'" " blocks starting at block `blk#'\n" " to/from memory address `addr'\n");U_BOOT_CMD( diskboot, 3, 1, do_diskboot, "diskboot- boot from IDE device\n", "loadAddr dev:part\n");#endif /* CONFIG_COMMANDS & CFG_CMD_IDE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -