|
|
1.1 ! root 1: /* ! 2: * Creation Date: <2003/12/11 21:23:54 samuel> ! 3: * Time-stamp: <2004/01/07 19:38:45 samuel> ! 4: * ! 5: * <osi-scsi.c> ! 6: * ! 7: * SCSI device node ! 8: * ! 9: * Copyright (C) 2003, 2004 Samuel Rydh ([email protected]) ! 10: * ! 11: * This program is free software; you can redistribute it and/or ! 12: * modify it under the terms of the GNU General Public License ! 13: * version 2 ! 14: * ! 15: */ ! 16: ! 17: #include "config.h" ! 18: #include "libopenbios/bindings.h" ! 19: #include "mol/mol.h" ! 20: #include "scsi_sh.h" ! 21: #include "osi_calls.h" ! 22: ! 23: #define MAX_TARGETS 32 ! 24: ! 25: typedef struct { ! 26: int probed; ! 27: int valid; /* a useable device found */ ! 28: ! 29: int is_cd; ! 30: int blocksize; ! 31: } target_info_t; ! 32: ! 33: static target_info_t scsi_devs[ MAX_TARGETS ]; ! 34: ! 35: typedef struct { ! 36: int target; ! 37: target_info_t *info; ! 38: } instance_data_t; ! 39: ! 40: ! 41: DECLARE_NODE( scsi, INSTALL_OPEN, sizeof(instance_data_t), ! 42: "/pci/pci-bridge/mol-scsi/sd", "/mol/mol-scsi/sd" ); ! 43: ! 44: ! 45: static int ! 46: scsi_cmd_( instance_data_t *sd, const char *cmd, int cmdlen, char *dest, ! 47: int len, int prelen, int postlen ) ! 48: { ! 49: char prebuf[4096], postbuf[4096]; ! 50: scsi_req_t r[2]; /* the [2] is a hack to get space for the sg-list */ ! 51: char sb[32]; ! 52: ! 53: /* memset( dest, 0, len ); */ ! 54: ! 55: if( (unsigned int)prelen > sizeof(prebuf) || (unsigned int)postlen > sizeof(postbuf) ) { ! 56: printk("bad pre/post len %d %d\n", prelen, postlen ); ! 57: return 1; ! 58: } ! 59: ! 60: memset( r, 0, sizeof(r[0]) ); ! 61: r->lun = 0; ! 62: r->target = sd->target; ! 63: r->is_write = 0; ! 64: memcpy( r->cdb, cmd, cmdlen ); ! 65: r->client_addr = (int)&r; ! 66: r->cdb_len = cmdlen; ! 67: r->sense[0].base = (int)&sb; ! 68: r->sense[0].size = sizeof(sb); ! 69: r->size = prelen + len + postlen; ! 70: r->n_sg = 3; ! 71: r->sglist.n_el = 3; ! 72: r->sglist.vec[0].base = (int)prebuf; ! 73: r->sglist.vec[0].size = prelen; ! 74: r->sglist.vec[1].base = (int)dest; ! 75: r->sglist.vec[1].size = len; ! 76: r->sglist.vec[2].base = (int)postbuf; ! 77: r->sglist.vec[2].size = postlen; ! 78: ! 79: if( OSI_SCSISubmit((int)&r) ) { ! 80: printk("OSI_SCSISubmit: error!\n"); ! 81: return 1; ! 82: } ! 83: while( !OSI_SCSIAck() ) ! 84: OSI_USleep( 10 ); ! 85: ! 86: if( r->adapter_status ) ! 87: return -1; ! 88: if( r->scsi_status ) ! 89: return ((sb[2] & 0xf) << 16) | (sb[12] << 8) | sb[13]; ! 90: return 0; ! 91: } ! 92: ! 93: static int ! 94: scsi_cmd( instance_data_t *sd, const char *cmd, int cmdlen ) ! 95: { ! 96: return scsi_cmd_( sd, cmd, cmdlen, NULL, 0, 0, 0 ); ! 97: } ! 98: ! 99: /* ( buf blk nblks -- actual ) */ ! 100: static void ! 101: scsi_read_blocks( instance_data_t *sd ) ! 102: { ! 103: int nblks = POP(); ! 104: int blk = POP(); ! 105: char *dest = (char*)POP(); ! 106: unsigned char cmd[10]; ! 107: int len = nblks * sd->info->blocksize; ! 108: ! 109: memset( dest, 0, len ); ! 110: ! 111: /* printk("READ: blk: %d length %d\n", blk, len ); */ ! 112: memset( cmd, 0, sizeof(cmd) ); ! 113: cmd[0] = 0x28; /* READ_10 */ ! 114: cmd[2] = blk >> 24; ! 115: cmd[3] = blk >> 16; ! 116: cmd[4] = blk >> 8; ! 117: cmd[5] = blk; ! 118: cmd[7] = nblks >> 8; ! 119: cmd[8] = nblks; ! 120: ! 121: if( scsi_cmd_(sd, cmd, 10, dest, len, 0, 0) ) { ! 122: printk("read: scsi_cmd failed\n"); ! 123: RET( -1 ); ! 124: } ! 125: PUSH( nblks ); ! 126: } ! 127: ! 128: static int ! 129: inquiry( instance_data_t *sd ) ! 130: { ! 131: char inquiry_cmd[6] = { 0x12, 0, 0, 0, 32, 0 }; ! 132: char start_stop_unit_cmd[6] = { 0x1b, 0, 0, 0, 1, 0 }; ! 133: char test_unit_ready_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; ! 134: char prev_allow_medium_removal[6] = { 0x1e, 0, 0, 0, 1, 0 }; ! 135: char set_cd_speed_cmd[12] = { 0xbb, 0, 0xff, 0xff, 0xff, 0xff, ! 136: 0, 0, 0, 0, 0, 0 }; ! 137: target_info_t *info = &scsi_devs[sd->target]; ! 138: char ret[32]; ! 139: int i, sense; ! 140: ! 141: if( sd->target >= MAX_TARGETS ) ! 142: return -1; ! 143: sd->info = info; ! 144: ! 145: if( info->probed ) ! 146: return info->valid ? 0:-1; ! 147: info->probed = 1; ! 148: ! 149: if( (sense=scsi_cmd_(sd, inquiry_cmd, 6, ret, 2, 0, 0)) ) { ! 150: if( sense < 0 ) ! 151: return -1; ! 152: printk("INQUIRY failed\n"); ! 153: return -1; ! 154: } ! 155: ! 156: /* medium present? */ ! 157: if( (scsi_cmd(sd, test_unit_ready_cmd, 6) >> 8) == 0x23a ) { ! 158: printk("no media\n"); ! 159: return -1; ! 160: } ! 161: ! 162: info->is_cd = 0; ! 163: info->blocksize = 512; ! 164: ! 165: if( ret[0] == 5 /* CD/DVD */ ) { ! 166: info->blocksize = 2048; ! 167: info->is_cd = 1; ! 168: ! 169: scsi_cmd( sd, prev_allow_medium_removal, 6 ); ! 170: scsi_cmd( sd, set_cd_speed_cmd, 12 ); ! 171: scsi_cmd( sd, start_stop_unit_cmd, 6 ); ! 172: ! 173: } else if( ret[0] == 0 /* DISK */ ) { ! 174: scsi_cmd( sd, test_unit_ready_cmd, 6 ); ! 175: scsi_cmd( sd, start_stop_unit_cmd, 6 ); ! 176: } else { ! 177: /* don't boot from this device (could be a scanner :-)) */ ! 178: return -1; ! 179: } ! 180: ! 181: /* wait for spin-up (or whatever) to complete */ ! 182: for( i=0; ; i++ ) { ! 183: if( i > 300 ) { ! 184: printk("SCSI timeout (sense %x)\n", sense ); ! 185: return -1; ! 186: } ! 187: sense = scsi_cmd( sd, test_unit_ready_cmd, 6 ); ! 188: if( (sense & 0xf0000) == 0x20000 ) { ! 189: OSI_USleep( 10000 ); ! 190: continue; ! 191: } ! 192: break; ! 193: } ! 194: ! 195: info->valid = 1; ! 196: return 0; ! 197: } ! 198: ! 199: /* ( -- success? ) */ ! 200: static void ! 201: scsi_open( instance_data_t *sd ) ! 202: { ! 203: static int once = 0; ! 204: phandle_t ph; ! 205: ! 206: fword("my-unit"); ! 207: sd->target = POP(); ! 208: ! 209: if( !once ) { ! 210: once++; ! 211: OSI_SCSIControl( SCSI_CTRL_INIT, 0 ); ! 212: } ! 213: ! 214: /* obtiain device information */ ! 215: if( inquiry(sd) ) ! 216: RET(0); ! 217: ! 218: selfword("open-deblocker"); ! 219: ! 220: /* interpose disk-label */ ! 221: ph = find_dev("/packages/disk-label"); ! 222: fword("my-args"); ! 223: PUSH_ph( ph ); ! 224: fword("interpose"); ! 225: ! 226: PUSH( -1 ); ! 227: } ! 228: ! 229: /* ( -- ) */ ! 230: static void ! 231: scsi_close( instance_data_t *pb ) ! 232: { ! 233: selfword("close-deblocker"); ! 234: } ! 235: ! 236: ! 237: /* ( -- bs ) */ ! 238: static void ! 239: scsi_block_size( instance_data_t *sd ) ! 240: { ! 241: PUSH( sd->info->blocksize ); ! 242: } ! 243: ! 244: /* ( -- maxbytes ) */ ! 245: static void ! 246: scsi_max_transfer( instance_data_t *sd ) ! 247: { ! 248: PUSH( 1024*1024 ); ! 249: } ! 250: ! 251: static void ! 252: scsi_initialize( instance_data_t *sd ) ! 253: { ! 254: fword("is-deblocker"); ! 255: } ! 256: ! 257: ! 258: NODE_METHODS( scsi ) = { ! 259: { NULL, scsi_initialize }, ! 260: { "open", scsi_open }, ! 261: { "close", scsi_close }, ! 262: { "read-blocks", scsi_read_blocks }, ! 263: { "block-size", scsi_block_size }, ! 264: { "max-transfer", scsi_max_transfer }, ! 265: }; ! 266: ! 267: void ! 268: osiscsi_init( void ) ! 269: { ! 270: REGISTER_NODE( scsi ); ! 271: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.