2 * Creation Date: <2003/12/11 21:23:54 samuel>
3 * Time-stamp: <2004/01/07 19:38:45 samuel>
9 * Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
18 #include "libopenbios/bindings.h"
21 #include "osi_calls.h"
23 #define MAX_TARGETS 32
27 int valid; /* a useable device found */
33 static target_info_t scsi_devs[ MAX_TARGETS ];
41 DECLARE_NODE( scsi, INSTALL_OPEN, sizeof(instance_data_t),
42 "/pci/pci-bridge/mol-scsi/sd", "/mol/mol-scsi/sd" );
46 scsi_cmd_( instance_data_t *sd, const char *cmd, int cmdlen, char *dest,
47 int len, int prelen, int postlen )
49 char prebuf[4096], postbuf[4096];
50 scsi_req_t r[2]; /* the [2] is a hack to get space for the sg-list */
53 /* memset( dest, 0, len ); */
55 if( (unsigned int)prelen > sizeof(prebuf) || (unsigned int)postlen > sizeof(postbuf) ) {
56 printk("bad pre/post len %d %d\n", prelen, postlen );
60 memset( r, 0, sizeof(r[0]) );
62 r->target = sd->target;
64 memcpy( r->cdb, cmd, cmdlen );
65 r->client_addr = (int)&r;
67 r->sense[0].base = (int)&sb;
68 r->sense[0].size = sizeof(sb);
69 r->size = prelen + len + postlen;
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;
79 if( OSI_SCSISubmit((int)&r) ) {
80 printk("OSI_SCSISubmit: error!\n");
83 while( !OSI_SCSIAck() )
86 if( r->adapter_status )
89 return ((sb[2] & 0xf) << 16) | (sb[12] << 8) | sb[13];
94 scsi_cmd( instance_data_t *sd, const char *cmd, int cmdlen )
96 return scsi_cmd_( sd, cmd, cmdlen, NULL, 0, 0, 0 );
99 /* ( buf blk nblks -- actual ) */
101 scsi_read_blocks( instance_data_t *sd )
105 char *dest = (char*)POP();
106 unsigned char cmd[10];
107 int len = nblks * sd->info->blocksize;
109 memset( dest, 0, len );
111 /* printk("READ: blk: %d length %d\n", blk, len ); */
112 memset( cmd, 0, sizeof(cmd) );
113 cmd[0] = 0x28; /* READ_10 */
121 if( scsi_cmd_(sd, cmd, 10, dest, len, 0, 0) ) {
122 printk("read: scsi_cmd failed\n");
129 inquiry( instance_data_t *sd )
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,
137 target_info_t *info = &scsi_devs[sd->target];
141 if( sd->target >= MAX_TARGETS )
146 return info->valid ? 0:-1;
149 if( (sense=scsi_cmd_(sd, inquiry_cmd, 6, ret, 2, 0, 0)) ) {
152 printk("INQUIRY failed\n");
156 /* medium present? */
157 if( (scsi_cmd(sd, test_unit_ready_cmd, 6) >> 8) == 0x23a ) {
158 printk("no media\n");
163 info->blocksize = 512;
165 if( ret[0] == 5 /* CD/DVD */ ) {
166 info->blocksize = 2048;
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 );
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 );
177 /* don't boot from this device (could be a scanner :-)) */
181 /* wait for spin-up (or whatever) to complete */
184 printk("SCSI timeout (sense %x)\n", sense );
187 sense = scsi_cmd( sd, test_unit_ready_cmd, 6 );
188 if( (sense & 0xf0000) == 0x20000 ) {
199 /* ( -- success? ) */
201 scsi_open( instance_data_t *sd )
211 OSI_SCSIControl( SCSI_CTRL_INIT, 0 );
214 /* obtiain device information */
218 selfword("open-deblocker");
220 /* interpose disk-label */
221 ph = find_dev("/packages/disk-label");
231 scsi_close( instance_data_t *pb )
233 selfword("close-deblocker");
239 scsi_block_size( instance_data_t *sd )
241 PUSH( sd->info->blocksize );
244 /* ( -- maxbytes ) */
246 scsi_max_transfer( instance_data_t *sd )
252 scsi_initialize( instance_data_t *sd )
254 fword("is-deblocker");
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 },
270 REGISTER_NODE( scsi );