|
|
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.