📄 cmd_scsi.c
字号:
/* * (C) Copyright 2001 * Denis Peter, MPL AG Switzerland * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * *//* * SCSI support. */#include <common.h>#include <command.h>#include <asm/processor.h>#include <scsi.h>#include <image.h>#include <pci.h>#undef SCSI_DEBUG#ifdef SCSI_DEBUG#define PRINTF(fmt,args...) printf (fmt ,##args)#else#define PRINTF(fmt,args...)#endif#if (CONFIG_COMMANDS & CFG_CMD_SCSI)#ifdef CONFIG_SCSI_SYM53C8XX#define SCSI_VEND_ID 0x1000#ifndef CONFIG_SCSI_DEV_ID#define SCSI_DEV_ID 0x0001#else#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID#endif#else#error CONFIG_SCSI_SYM53C8XX must be defined#endifstatic ccb tempccb; /* temporary scsi command buffer */static unsigned char tempbuff[512]; /* temporary data buffer */static int scsi_max_devs; /* number of highest available scsi device */static int scsi_curr_dev; /* current device */static block_dev_desc_t scsi_dev_desc[CFG_SCSI_MAX_DEVICE];/******************************************************************************** * forward declerations of some Setup Routines */void scsi_setup_test_unit_ready(ccb * pccb);void scsi_setup_read_capacity(ccb * pccb);void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks);void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks);void scsi_setup_inquiry(ccb * pccb);void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);ulong scsi_read(int device, ulong blknr, ulong blkcnt, ulong *buffer);/********************************************************************************* * (re)-scan the scsi bus and reports scsi device info * to the user if mode = 1 */void scsi_scan(int mode){ unsigned char i,perq,modi,lun; unsigned long capacity,blksz; ccb* pccb=(ccb *)&tempccb; if(mode==1) { printf("scanning bus for devices...\n"); } for(i=0;i<CFG_SCSI_MAX_DEVICE;i++) { scsi_dev_desc[i].target=0xff; scsi_dev_desc[i].lun=0xff; scsi_dev_desc[i].lba=0; scsi_dev_desc[i].blksz=0; scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN; scsi_dev_desc[i].vendor[0]=0; scsi_dev_desc[i].product[0]=0; scsi_dev_desc[i].revision[0]=0; scsi_dev_desc[i].removable=FALSE; scsi_dev_desc[i].if_type=IF_TYPE_SCSI; scsi_dev_desc[i].dev=i; scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN; scsi_dev_desc[i].block_read=scsi_read; } scsi_max_devs=0; for(i=0;i<CFG_SCSI_MAX_SCSI_ID;i++) { pccb->target=i; for(lun=0;lun<CFG_SCSI_MAX_LUN;lun++) { pccb->lun=lun; pccb->pdata=(unsigned char *)&tempbuff; pccb->datalen=512; scsi_setup_inquiry(pccb); if(scsi_exec(pccb)!=TRUE) { if(pccb->contr_stat==SCSI_SEL_TIME_OUT) { PRINTF("Selection timeout ID %d\n",pccb->target); continue; /* selection timeout => assuming no device present */ } scsi_print_error(pccb); continue; } perq=tempbuff[0]; modi=tempbuff[1]; if((perq & 0x1f)==0x1f) { continue; /* skip unknown devices */ } if((modi&0x80)==0x80) /* drive is removable */ scsi_dev_desc[scsi_max_devs].removable=TRUE; /* get info for this device */ scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].vendor[0],&tempbuff[8],8); scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].product[0],&tempbuff[16],16); scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].revision[0],&tempbuff[32],4); scsi_dev_desc[scsi_max_devs].target=pccb->target; scsi_dev_desc[scsi_max_devs].lun=pccb->lun; pccb->datalen=0; scsi_setup_test_unit_ready(pccb); if(scsi_exec(pccb)!=TRUE) { if(scsi_dev_desc[scsi_max_devs].removable==TRUE) { scsi_dev_desc[scsi_max_devs].type=perq; goto removable; } scsi_print_error(pccb); continue; } pccb->datalen=8; scsi_setup_read_capacity(pccb); if(scsi_exec(pccb)!=TRUE) { scsi_print_error(pccb); continue; } capacity=((unsigned long)tempbuff[0]<<24)|((unsigned long)tempbuff[1]<<16)| ((unsigned long)tempbuff[2]<<8)|((unsigned long)tempbuff[3]); blksz=((unsigned long)tempbuff[4]<<24)|((unsigned long)tempbuff[5]<<16)| ((unsigned long)tempbuff[6]<<8)|((unsigned long)tempbuff[7]); scsi_dev_desc[scsi_max_devs].lba=capacity; scsi_dev_desc[scsi_max_devs].blksz=blksz; scsi_dev_desc[scsi_max_devs].type=perq; init_part(&scsi_dev_desc[scsi_max_devs]);removable: if(mode==1) { printf (" Device %d: ", scsi_max_devs); dev_print(&scsi_dev_desc[scsi_max_devs]); } /* if mode */ scsi_max_devs++; } /* next LUN */ } if(scsi_max_devs>0) scsi_curr_dev=0; else scsi_curr_dev=-1;}void scsi_init(void){ int busdevfunc; busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */ if(busdevfunc==-1) { printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID); return; }#ifdef DEBUG else { printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7); }#endif scsi_low_level_init(busdevfunc); scsi_scan(1);}block_dev_desc_t * scsi_get_dev(int dev){ return((block_dev_desc_t *)&scsi_dev_desc[dev]);}/****************************************************************************** * scsi boot command intepreter. Derived from diskboot */int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ char *boot_device = NULL; char *ep; int dev, part = 0; ulong cnt; ulong addr; disk_partition_t info; image_header_t *hdr; int rcode = 0; switch (argc) { case 1: addr = CFG_LOAD_ADDR; boot_device = getenv ("bootdevice"); break; case 2: addr = simple_strtoul(argv[1], NULL, 16); boot_device = getenv ("bootdevice"); break; case 3: addr = simple_strtoul(argv[1], NULL, 16); boot_device = argv[2]; break; default: printf ("Usage:\n%s\n", cmdtp->usage); return 1; } if (!boot_device) { puts ("\n** No boot device **\n"); return 1; } dev = simple_strtoul(boot_device, &ep, 16); printf("booting from dev %d\n",dev); if (scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) { printf ("\n** Device %d not available\n", dev); return 1; } if (*ep) { if (*ep != ':') { puts ("\n** Invalid boot device, use `dev[:part]' **\n"); return 1; } part = simple_strtoul(++ep, NULL, 16); } if (get_partition_info (&scsi_dev_desc[dev], part, &info)) { printf("error reading partinfo\n"); return 1; } if ((strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) && (strncmp(info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) { printf ("\n** Invalid partition type \"%.32s\"" " (expect \"" BOOT_PART_TYPE "\")\n", info.type); return 1; } printf ("\nLoading from SCSI device %d, partition %d: " "Name: %.32s Type: %.32s\n", dev, part, info.name, info.type); PRINTF ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n", info.start, info.size, info.blksz); if (scsi_read (dev, info.start, 1, (ulong *)addr) != 1) { printf ("** Read error on %d:%d\n", dev, part); return 1; } hdr = (image_header_t *)addr; if (hdr->ih_magic == IH_MAGIC) { print_image_hdr (hdr); cnt = (hdr->ih_size + sizeof(image_header_t)); cnt += info.blksz - 1; cnt /= info.blksz; cnt -= 1; } else { printf("\n** Bad Magic Number **\n"); return 1; } if (scsi_read (dev, info.start+1, cnt, (ulong *)(addr+info.blksz)) != cnt) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -