|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2010 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stddef.h> ! 22: #include <stdlib.h> ! 23: #include <string.h> ! 24: #include <errno.h> ! 25: #include <byteswap.h> ! 26: #include <ipxe/interface.h> ! 27: #include <ipxe/iobuf.h> ! 28: #include <ipxe/process.h> ! 29: #include <ipxe/xfer.h> ! 30: #include <ipxe/fc.h> ! 31: #include <ipxe/fcns.h> ! 32: ! 33: /** @file ! 34: * ! 35: * Fibre Channel name server lookups ! 36: * ! 37: */ ! 38: ! 39: /** A Fibre Channel name server query */ ! 40: struct fc_ns_query { ! 41: /** Reference count */ ! 42: struct refcnt refcnt; ! 43: /** Fibre Channel exchange */ ! 44: struct interface xchg; ! 45: ! 46: /** Fibre Channel peer */ ! 47: struct fc_peer *peer; ! 48: /** Fibre Channel port */ ! 49: struct fc_port *port; ! 50: ! 51: /** Process */ ! 52: struct process process; ! 53: /** Success handler ! 54: * ! 55: * @v peer Fibre Channel peer ! 56: * @v port Fibre Channel port ! 57: * @v peer_port_id Peer port ID ! 58: * @ret rc Return status code ! 59: */ ! 60: int ( * done ) ( struct fc_peer *peer, struct fc_port *port, ! 61: struct fc_port_id *peer_port_id ); ! 62: }; ! 63: ! 64: /** ! 65: * Free name server query ! 66: * ! 67: * @v refcnt Reference count ! 68: */ ! 69: static void fc_ns_query_free ( struct refcnt *refcnt ) { ! 70: struct fc_ns_query *query = ! 71: container_of ( refcnt, struct fc_ns_query, refcnt ); ! 72: ! 73: fc_peer_put ( query->peer ); ! 74: fc_port_put ( query->port ); ! 75: free ( query ); ! 76: } ! 77: ! 78: /** ! 79: * Close name server query ! 80: * ! 81: * @v query Name server query ! 82: * @v rc Reason for close ! 83: */ ! 84: static void fc_ns_query_close ( struct fc_ns_query *query, int rc ) { ! 85: ! 86: /* Stop process */ ! 87: process_del ( &query->process ); ! 88: ! 89: /* Shut down interfaces */ ! 90: intf_shutdown ( &query->xchg, rc ); ! 91: } ! 92: ! 93: /** ! 94: * Receive name server query response ! 95: * ! 96: * @v query Name server query ! 97: * @v iobuf I/O buffer ! 98: * @v meta Data transfer metadata ! 99: * @ret rc Return status code ! 100: */ ! 101: static int fc_ns_query_deliver ( struct fc_ns_query *query, ! 102: struct io_buffer *iobuf, ! 103: struct xfer_metadata *meta __unused ) { ! 104: union fc_ns_response *resp = iobuf->data; ! 105: struct fc_port_id *peer_port_id; ! 106: int rc; ! 107: ! 108: /* Sanity check */ ! 109: if ( iob_len ( iobuf ) < sizeof ( resp->ct ) ) { ! 110: DBGC ( query, "FCNS %p received underlength response (%zd " ! 111: "bytes)\n", query, iob_len ( iobuf ) ); ! 112: rc = -EINVAL; ! 113: goto done; ! 114: } ! 115: ! 116: /* Handle response */ ! 117: switch ( ntohs ( resp->ct.code ) ) { ! 118: case FC_GS_ACCEPT: ! 119: if ( iob_len ( iobuf ) < sizeof ( resp->gid_pn ) ) { ! 120: DBGC ( query, "FCNS %p received underlength accept " ! 121: "response (%zd bytes)\n", ! 122: query, iob_len ( iobuf ) ); ! 123: rc = -EINVAL; ! 124: goto done; ! 125: } ! 126: peer_port_id = &resp->gid_pn.port_id.port_id; ! 127: DBGC ( query, "FCNS %p resolved %s to %s via %s\n", ! 128: query, fc_ntoa ( &query->peer->port_wwn ), ! 129: fc_id_ntoa ( peer_port_id ), query->port->name ); ! 130: if ( ( rc = query->done ( query->peer, query->port, ! 131: peer_port_id ) ) != 0 ) ! 132: goto done; ! 133: break; ! 134: case FC_GS_REJECT: ! 135: DBGC ( query, "FCNS %p rejected (reason %02x explanation " ! 136: "%02x)\n", query, resp->reject.ct.reason, ! 137: resp->reject.ct.explanation ); ! 138: break; ! 139: default: ! 140: DBGC ( query, "FCNS %p received invalid response code %04x\n", ! 141: query, ntohs ( resp->ct.code ) ); ! 142: rc = -ENOTSUP; ! 143: goto done; ! 144: } ! 145: ! 146: rc = 0; ! 147: done: ! 148: free_iob ( iobuf ); ! 149: fc_ns_query_close ( query, rc ); ! 150: return rc; ! 151: } ! 152: ! 153: /** ! 154: * Name server query process ! 155: * ! 156: * @v process Process ! 157: */ ! 158: static void fc_ns_query_step ( struct process *process ) { ! 159: struct fc_ns_query *query = ! 160: container_of ( process, struct fc_ns_query, process ); ! 161: struct xfer_metadata meta; ! 162: struct fc_ns_gid_pn_request gid_pn; ! 163: int xchg_id; ! 164: int rc; ! 165: ! 166: /* Stop process */ ! 167: process_del ( &query->process ); ! 168: ! 169: /* Create exchange */ ! 170: if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port, ! 171: &fc_gs_port_id, ! 172: FC_TYPE_CT ) ) < 0 ) { ! 173: rc = xchg_id; ! 174: DBGC ( query, "FCNS %p could not create exchange: %s\n", ! 175: query, strerror ( rc ) ); ! 176: fc_ns_query_close ( query, rc ); ! 177: return; ! 178: } ! 179: ! 180: /* Construct query request */ ! 181: memset ( &gid_pn, 0, sizeof ( gid_pn ) ); ! 182: gid_pn.ct.revision = FC_CT_REVISION; ! 183: gid_pn.ct.type = FC_GS_TYPE_DS; ! 184: gid_pn.ct.subtype = FC_DS_SUBTYPE_NAME; ! 185: gid_pn.ct.code = htons ( FC_NS_GET ( FC_NS_PORT_NAME, FC_NS_PORT_ID )); ! 186: memcpy ( &gid_pn.port_wwn, &query->peer->port_wwn, ! 187: sizeof ( gid_pn.port_wwn ) ); ! 188: memset ( &meta, 0, sizeof ( meta ) ); ! 189: meta.flags = XFER_FL_OVER; ! 190: ! 191: /* Send query */ ! 192: if ( ( rc = xfer_deliver_raw_meta ( &query->xchg, &gid_pn, ! 193: sizeof ( gid_pn ), &meta ) ) != 0){ ! 194: DBGC ( query, "FCNS %p could not deliver query: %s\n", ! 195: query, strerror ( rc ) ); ! 196: fc_ns_query_close ( query, rc ); ! 197: return; ! 198: } ! 199: } ! 200: ! 201: /** Name server exchange interface operations */ ! 202: static struct interface_operation fc_ns_query_xchg_op[] = { ! 203: INTF_OP ( xfer_deliver, struct fc_ns_query *, fc_ns_query_deliver ), ! 204: INTF_OP ( intf_close, struct fc_ns_query *, fc_ns_query_close ), ! 205: }; ! 206: ! 207: /** Name server exchange interface descriptor */ ! 208: static struct interface_descriptor fc_ns_query_xchg_desc = ! 209: INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op ); ! 210: ! 211: /** ! 212: * Issue Fibre Channel name server query ! 213: * ! 214: * @v peer Fibre Channel peer ! 215: * @v port Fibre Channel port ! 216: * @ret rc Return status code ! 217: */ ! 218: int fc_ns_query ( struct fc_peer *peer, struct fc_port *port, ! 219: int ( * done ) ( struct fc_peer *peer, struct fc_port *port, ! 220: struct fc_port_id *peer_port_id ) ) { ! 221: struct fc_ns_query *query; ! 222: ! 223: /* Allocate and initialise structure */ ! 224: query = zalloc ( sizeof ( *query ) ); ! 225: if ( ! query ) ! 226: return -ENOMEM; ! 227: ref_init ( &query->refcnt, fc_ns_query_free ); ! 228: intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt ); ! 229: process_init ( &query->process, fc_ns_query_step, &query->refcnt ); ! 230: query->peer = fc_peer_get ( peer ); ! 231: query->port = fc_port_get ( port ); ! 232: query->done = done; ! 233: ! 234: DBGC ( query, "FCNS %p querying %s via %s\n", ! 235: query, fc_ntoa ( &query->peer->port_wwn ), port->name ); ! 236: ! 237: /* Mortalise self and return */ ! 238: ref_put ( &query->refcnt ); ! 239: return 0; ! 240: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.