|
|
1.1.1.3 ! root 1: /* $Id: scsi.c,v 1.3 2007/01/07 23:27:50 fredette Exp $ */ 1.1 root 2: 3: /* generic/scsi.c - generic SCSI implementation support: */ 4: 5: /* 6: * Copyright (c) 2003 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.3 ! root 37: _TME_RCSID("$Id: scsi.c,v 1.3 2007/01/07 23:27:50 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/scsi.h> 1.1.1.3 ! root 41: #include <tme/scsi/scsi-cdb.h> ! 42: #include <tme/scsi/scsi-msg.h> 1.1 root 43: #include <stdlib.h> 44: 45: /* this scores a SCSI connection: */ 46: int 47: tme_scsi_connection_score(struct tme_connection *conn, unsigned int *_score) 48: { 49: struct tme_scsi_connection *conn_scsi; 50: struct tme_scsi_connection *conn_scsi_other; 51: 52: /* both sides must be SCSI connections: */ 53: assert(conn->tme_connection_type == TME_CONNECTION_SCSI); 54: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_SCSI); 55: 56: /* you cannot connect a bus to a bus, or a device to a device: */ 57: conn_scsi 58: = (struct tme_scsi_connection *) conn; 59: conn_scsi_other 60: = (struct tme_scsi_connection *) conn->tme_connection_other; 1.1.1.2 root 61: /* XXX we need a way to distinguish a bus from a device: */ 1.1 root 62: *_score 1.1.1.2 root 63: = 1; 1.1 root 64: return (TME_OK); 65: } 66: 67: /* this parses a SCSI ID: */ 68: int 69: tme_scsi_id_parse(const char *id_string) 70: { 71: unsigned long id; 72: char *p1; 73: 74: /* catch a NULL string: */ 75: if (id_string == NULL) { 76: return (-1); 77: } 78: 79: /* convert the string: */ 80: id = strtoul(id_string, &p1, 0); 81: if (p1 == id_string 82: || *p1 != '\0') { 83: return (-1); 84: } 85: return (id); 86: } 1.1.1.3 ! root 87: ! 88: /* this implements state machines that determine the residual in a ! 89: SCSI command or message phase: */ ! 90: tme_uint32_t ! 91: tme_scsi_phase_resid(tme_scsi_control_t scsi_control, ! 92: tme_uint32_t *_state, ! 93: const tme_shared tme_uint8_t *bytes, ! 94: unsigned long count) ! 95: { ! 96: #define _TME_SCSI_PHASE_RESID_STATE_COUNT_MASK (4095) ! 97: tme_uint32_t state; ! 98: tme_uint32_t transferred; ! 99: tme_uint32_t seen; ! 100: tme_uint32_t skip; ! 101: tme_uint32_t resid; ! 102: tme_uint8_t byte; ! 103: ! 104: /* get the opaque state, which must not be the value zero (the ! 105: opaque stop state): */ ! 106: state = *_state; ! 107: assert (state != 0); ! 108: ! 109: /* decompose the opaque state. NB since the opaque start state for ! 110: all SCSI bus phases is the value one, and we use internal state ! 111: zero to represent the stop state, we subtract one from the bytes ! 112: transferred value and add one to the internal state number: */ ! 113: transferred = (state - 1) & _TME_SCSI_PHASE_RESID_STATE_COUNT_MASK; ! 114: state /= (_TME_SCSI_PHASE_RESID_STATE_COUNT_MASK + 1); ! 115: seen = state & _TME_SCSI_PHASE_RESID_STATE_COUNT_MASK; ! 116: state = (state / (_TME_SCSI_PHASE_RESID_STATE_COUNT_MASK + 1)) + 1; ! 117: ! 118: /* we can't have transferred more than we've seen: */ ! 119: assert (transferred <= seen); ! 120: ! 121: /* start with a residual of the number of bytes that we have already ! 122: seen, and skip past those bytes in the buffer: */ ! 123: resid = seen - transferred; ! 124: skip = TME_MIN(resid, count); ! 125: bytes += skip; ! 126: count -= skip; ! 127: ! 128: /* loop over the bytes: */ ! 129: for (; count > 0; ) { ! 130: ! 131: /* get this next byte: */ ! 132: byte = *(bytes++); ! 133: count--; ! 134: seen++; ! 135: ! 136: /* dispatch on the SCSI bus phase: */ ! 137: switch (TME_SCSI_PHASE(scsi_control)) { ! 138: ! 139: /* an unknown bus phase: */ ! 140: default: assert(FALSE); ! 141: ! 142: case TME_SCSI_PHASE_COMMAND: ! 143: ! 144: /* we only have state one. transfer the number of bytes in the ! 145: CDB and move to the stop state: */ ! 146: assert (state == 1); ! 147: switch (byte & TME_SCSI_CDB_GROUP_MASK) { ! 148: default: abort(); ! 149: case TME_SCSI_CDB_GROUP_0: resid += TME_SCSI_CDB_GROUP_0_LEN; break; ! 150: case TME_SCSI_CDB_GROUP_1: resid += TME_SCSI_CDB_GROUP_1_LEN; break; ! 151: case TME_SCSI_CDB_GROUP_2: resid += TME_SCSI_CDB_GROUP_2_LEN; break; ! 152: case TME_SCSI_CDB_GROUP_4: resid += TME_SCSI_CDB_GROUP_4_LEN; break; ! 153: case TME_SCSI_CDB_GROUP_5: resid += TME_SCSI_CDB_GROUP_5_LEN; break; ! 154: } ! 155: state = 0; ! 156: break; ! 157: ! 158: case TME_SCSI_PHASE_MESSAGE_IN: ! 159: case TME_SCSI_PHASE_MESSAGE_OUT: ! 160: ! 161: /* dispatch on the state: */ ! 162: switch (state) { ! 163: default: assert(FALSE); ! 164: ! 165: /* state one is the first byte of the message: */ ! 166: case 1: ! 167: ! 168: /* if this is an extended message: */ ! 169: if (byte == TME_SCSI_MSG_EXTENDED) { ! 170: ! 171: /* transfer this first message byte and move to state two: */ ! 172: resid += 1; ! 173: state = 2; ! 174: } ! 175: ! 176: /* otherwise, if this is a two-byte message: */ ! 177: else if (TME_SCSI_MSG_IS_2(byte)) { ! 178: ! 179: /* transfer the two message bytes and move to state zero: */ ! 180: resid += 2; ! 181: state = 0; ! 182: } ! 183: ! 184: /* otherwise, this is a one-byte message: */ ! 185: else { ! 186: ! 187: /* transfer the one message byte and move to state zero: */ ! 188: resid += 1; ! 189: state = 0; ! 190: } ! 191: break; ! 192: ! 193: /* the second byte of an extended message: */ ! 194: case 2: ! 195: ! 196: /* transfer this second message byte, followed by the extended ! 197: message itself, and move to state zero: */ ! 198: resid += (byte == 0 ? 1 + 256 : 1 + byte); ! 199: state = 0; ! 200: break; ! 201: } ! 202: break; ! 203: } ! 204: ! 205: /* if we've reached state zero, return the opaque stop state and ! 206: the detected residual: */ ! 207: if (state == 0) { ! 208: *_state = 0; ! 209: return (resid); ! 210: } ! 211: } ! 212: ! 213: /* compose the updated opaque state. NB since the opaque start ! 214: state for all SCSI bus phases is the value one, and we use ! 215: internal state zero to represent the stop state, we add one from ! 216: the bytes transferred value and subtract one to the internal ! 217: state number: */ ! 218: state = (state - 1) * (_TME_SCSI_PHASE_RESID_STATE_COUNT_MASK + 1); ! 219: state += seen; ! 220: state *= (_TME_SCSI_PHASE_RESID_STATE_COUNT_MASK + 1); ! 221: state += (transferred + 1) & _TME_SCSI_PHASE_RESID_STATE_COUNT_MASK; ! 222: *_state = state; ! 223: return (0); ! 224: #undef _TME_SCSI_PHASE_RESID_STATE_COUNT_MASK ! 225: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.