?? osi-scsi.c
字號:
/* * Creation Date: <2003/12/11 21:23:54 samuel> * Time-stamp: <2004/01/07 19:38:45 samuel> * * <osi-scsi.c> * * SCSI device node * * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 * */#include "openbios/config.h"#include "openbios/bindings.h"#include "mol/mol.h"#include "scsi_sh.h"#include "osi_calls.h"#define MAX_TARGETS 32typedef struct { int probed; int valid; /* a useable device found */ int is_cd; int blocksize;} target_info_t;static target_info_t scsi_devs[ MAX_TARGETS ];typedef struct { int target; target_info_t *info;} instance_data_t;DECLARE_NODE( scsi, INSTALL_OPEN, sizeof(instance_data_t), "/pci/pci-bridge/mol-scsi/sd", "/mol/mol-scsi/sd" );static intscsi_cmd_( instance_data_t *sd, const char *cmd, int cmdlen, char *dest, int len, int prelen, int postlen ){ char prebuf[4096], postbuf[4096]; scsi_req_t r[2]; /* the [2] is a hack to get space for the sg-list */ char sb[32]; /* memset( dest, 0, len ); */ if( (uint)prelen > sizeof(prebuf) || (uint)postlen > sizeof(postbuf) ) { printk("bad pre/post len %d %d\n", prelen, postlen ); return 1; } memset( r, 0, sizeof(r[0]) ); r->lun = 0; r->target = sd->target; r->is_write = 0; memcpy( r->cdb, cmd, cmdlen ); r->client_addr = (int)&r; r->cdb_len = cmdlen; r->sense[0].base = (int)&sb; r->sense[0].size = sizeof(sb); r->size = prelen + len + postlen; r->n_sg = 3; r->sglist.n_el = 3; r->sglist.vec[0].base = (int)prebuf; r->sglist.vec[0].size = prelen; r->sglist.vec[1].base = (int)dest; r->sglist.vec[1].size = len; r->sglist.vec[2].base = (int)postbuf; r->sglist.vec[2].size = postlen; if( OSI_SCSISubmit((int)&r) ) { printk("OSI_SCSISubmit: error!\n"); return 1; } while( !OSI_SCSIAck() ) OSI_USleep( 10 ); if( r->adapter_status ) return -1; if( r->scsi_status ) return ((sb[2] & 0xf) << 16) | (sb[12] << 8) | sb[13]; return 0;}static intscsi_cmd( instance_data_t *sd, const char *cmd, int cmdlen ){ return scsi_cmd_( sd, cmd, cmdlen, NULL, 0, 0, 0 );}/* ( buf blk nblks -- actual ) */static voidscsi_read_blocks( instance_data_t *sd ){ int nblks = POP(); int blk = POP(); char *dest = (char*)POP(); unsigned char cmd[10]; int len = nblks * sd->info->blocksize; memset( dest, 0, len ); /* printk("READ: blk: %d length %d\n", blk, len ); */ memset( cmd, 0, sizeof(cmd) ); cmd[0] = 0x28; /* READ_10 */ cmd[2] = blk >> 24; cmd[3] = blk >> 16; cmd[4] = blk >> 8; cmd[5] = blk; cmd[7] = nblks >> 8; cmd[8] = nblks; if( scsi_cmd_(sd, cmd, 10, dest, len, 0, 0) ) { printk("read: scsi_cmd failed\n"); RET( -1 ); } PUSH( nblks );}static intinquiry( instance_data_t *sd ){ char inquiry_cmd[6] = { 0x12, 0, 0, 0, 32, 0 }; char start_stop_unit_cmd[6] = { 0x1b, 0, 0, 0, 1, 0 }; char test_unit_ready_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; char prev_allow_medium_removal[6] = { 0x1e, 0, 0, 0, 1, 0 }; char set_cd_speed_cmd[12] = { 0xbb, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0 }; target_info_t *info = &scsi_devs[sd->target]; char ret[32]; int i, sense; if( sd->target >= MAX_TARGETS ) return -1; sd->info = info; if( info->probed ) return info->valid ? 0:-1; info->probed = 1; if( (sense=scsi_cmd_(sd, inquiry_cmd, 6, ret, 2, 0, 0)) ) { if( sense < 0 ) return -1; printk("INQUIRY failed\n"); return -1; } /* medium present? */ if( (scsi_cmd(sd, test_unit_ready_cmd, 6) >> 8) == 0x23a ) { printk("no media\n"); return -1; } info->is_cd = 0; info->blocksize = 512; if( ret[0] == 5 /* CD/DVD */ ) { info->blocksize = 2048; info->is_cd = 1; scsi_cmd( sd, prev_allow_medium_removal, 6 ); scsi_cmd( sd, set_cd_speed_cmd, 12 ); scsi_cmd( sd, start_stop_unit_cmd, 6 ); } else if( ret[0] == 0 /* DISK */ ) { scsi_cmd( sd, test_unit_ready_cmd, 6 ); scsi_cmd( sd, start_stop_unit_cmd, 6 ); } else { /* don't boot from this device (could be a scanner :-)) */ return -1; } /* wait for spin-up (or whatever) to complete */ for( i=0; ; i++ ) { if( i > 300 ) { printk("SCSI timeout (sense %x)\n", sense ); return -1; } sense = scsi_cmd( sd, test_unit_ready_cmd, 6 ); if( (sense & 0xf0000) == 0x20000 ) { OSI_USleep( 10000 ); continue; } break; } info->valid = 1; return 0;}/* ( -- success? ) */static voidscsi_open( instance_data_t *sd ){ static int once = 0; phandle_t ph; fword("my-unit"); sd->target = POP(); if( !once ) { once++; OSI_SCSIControl( SCSI_CTRL_INIT, 0 ); } /* obtiain device information */ if( inquiry(sd) ) RET(0); selfword("open-deblocker"); /* interpose disk-label */ ph = find_dev("/packages/disk-label"); fword("my-args"); PUSH_ph( ph ); fword("interpose"); PUSH( -1 );}/* ( -- ) */static voidscsi_close( instance_data_t *pb ){ selfword("close-deblocker");}/* ( -- bs ) */static voidscsi_block_size( instance_data_t *sd ){ PUSH( sd->info->blocksize );}/* ( -- maxbytes ) */static voidscsi_max_transfer( instance_data_t *sd ){ PUSH( 1024*1024 );}static voidscsi_initialize( instance_data_t *sd ){ fword("is-deblocker");}NODE_METHODS( scsi ) = { { NULL, scsi_initialize }, { "open", scsi_open }, { "close", scsi_close }, { "read-blocks", scsi_read_blocks }, { "block-size", scsi_block_size }, { "max-transfer", scsi_max_transfer },};voidosiscsi_init( void ){ REGISTER_NODE( scsi );}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -