1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2004 Cluster File Systems, Inc.
5 * Author: Frank Zago <fzago@systemfabricworks.com>
7 * This file is part of Lustre, http://www.lustre.org.
9 * Lustre is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * Lustre is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Lustre; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /*--------------------------------------------------------------------------*/
28 struct sa_request *alloc_sa_request(void)
30 struct sa_request *request;
34 PORTAL_ALLOC(request, sizeof(*request));
38 retval = gsi_dtgrm_pool_get(kibnal_data.gsi_pool_handle, &dtgrm);
40 CERROR("cannot get a datagram: %d\n", retval);
41 PORTAL_FREE(request, sizeof(*request));
45 memset(request, 0, sizeof(*request));
47 request->dtgrm_req = dtgrm;
48 request->retry = GSI_RETRY; /* retry the request up to 10 times */
53 void free_sa_request(struct sa_request *request)
56 if (request->dtgrm_req) {
57 gsi_dtgrm_pool_put(request->dtgrm_req);
60 if (request->dtgrm_resp) {
61 gsi_dtgrm_pool_put(request->dtgrm_resp);
64 PORTAL_FREE(request, sizeof(*request));
68 /*--------------------------------------------------------------------------*/
70 static void complete_sa_request(struct sa_request *request)
72 if (request->callback) {
73 request->callback(request);
75 complete(&request->signal);
80 sa_request_timeout_handler(unsigned long context)
82 struct sa_request *request = (struct sa_request *)context;
86 if (request->retry--) {
89 CDEBUG(D_NET, "timer expired for MAD TID "LPX64" - retrying (%d retry left)\n", request->mad->hdr.transact_id, request->retry);
90 retval = gsi_post_send_dtgrm(kibnal_data.gsi_handle, request->dtgrm_req);
92 CERROR("gsi_post_send_dtgrm failed: %d\n", retval);
96 /* restart the timer */
97 request->timer.expires = jiffies + (HZ * GSI_TIMEOUT);
98 add_timer(&request->timer);
103 CDEBUG(D_NET, "timer expired for MAD TID "LPX64" - no more retry\n", request->mad->hdr.transact_id);
108 request->status = ret;
109 complete_sa_request(request);
113 /*--------------------------------------------------------------------------*/
115 /* Send a SA request */
116 int vibnal_start_sa_request(struct sa_request *request)
122 CDEBUG (D_NET, "querying SA\n");
124 /* Put the request on the pending list and get a transaction ID. */
125 down(&kibnal_data.gsi_mutex);
127 list_add_tail(&request->list, &kibnal_data.gsi_pending);
129 up(&kibnal_data.gsi_mutex);
131 retval = gsi_post_send_dtgrm(kibnal_data.gsi_handle, request->dtgrm_req);
133 CERROR("gsi_post_send_dtgrm failed: %d\n", retval);
137 /* TODO: This might create a race condition if the response has
138 * already been received. */
139 init_timer(&request->timer);
140 request->timer.expires = jiffies + (HZ * GSI_TIMEOUT);
141 request->timer.data = (unsigned long)request;
142 request->timer.function = sa_request_timeout_handler;
143 add_timer(&request->timer);
145 CDEBUG(D_NET, "Posted MAD with TID= "LPX64"\n", request->mad->hdr.transact_id);
151 vibnal_mad_received_cb(gsi_class_handle_t handle, void *context, gsi_dtgrm_t *dtgrm)
153 sa_mad_v2_t *mad = (sa_mad_v2_t *) dtgrm->mad;
154 ib_service_record_v2_t *sr = (ib_service_record_v2_t *) mad->payload;
155 struct list_head *this;
156 struct sa_request *request;
158 CDEBUG(D_NET, "Received new MAD\n");
160 /* Validate the MAD */
161 if (mad->hdr.base_ver != MAD_IB_BASE_VERSION ||
162 mad->hdr.class != MAD_CLASS_SUBN_ADM ||
163 mad->hdr.class_ver != 2) {
164 CDEBUG(D_NET, "ignoring MAD (base_ver=%x, class=%x, class_ver=%x)\n",
165 mad->hdr.base_ver, mad->hdr.class, mad->hdr.class_ver);
169 /* We don't care about queries, only about responses */
170 if (mad->hdr.m.ms.r != 1) {
171 CDEBUG(D_NET, "ignoring MAD (response=%d)\n", mad->hdr.m.ms.r);
175 /* We only care about service records and path records. */
176 if (mad->hdr.attrib_id != SA_SERVICE_RECORD &&
177 mad->hdr.attrib_id != SA_PATH_RECORD) {
178 CDEBUG(D_NET, "ignoring MAD (attrib_id=%x)\n", mad->hdr.attrib_id);
182 /* Find the MAD request in our list */
185 down(&kibnal_data.gsi_mutex);
187 list_for_each(this, &kibnal_data.gsi_pending) {
188 struct sa_request *_request = list_entry(this, struct sa_request, list);
190 CDEBUG(D_NET, "Comparing pending MAD TID "LPX64" with incoming MAD TID "LPX64"\n",
191 _request->mad->hdr.transact_id, mad->hdr.transact_id);
193 if (_request->mad->hdr.transact_id == mad->hdr.transact_id) {
194 CDEBUG(D_NET, "TIDs match\n");
200 if (request == NULL) {
201 up(&kibnal_data.gsi_mutex);
202 CDEBUG(D_NET, "ignoring MAD (TID = "LPX64"\n", mad->hdr.transact_id);
206 up(&kibnal_data.gsi_mutex);
208 /* Stop the timer and remove the request from the pending list of requests. */
209 del_timer_sync(&request->timer);
211 down(&kibnal_data.gsi_mutex);
213 list_del(&request->list);
215 up(&kibnal_data.gsi_mutex);
217 request->dtgrm_resp = dtgrm;
219 /* Depending on the response, update the status. This is not exact
220 * because a non-zero status is not always an error, but that
221 * should be good enough right now. */
223 if (mad->hdr.u.ns.status.raw16) {
224 CDEBUG(D_NET, "MAD response has bad status: %x\n", mad->hdr.u.ns.status.raw16);
225 request->status = -EIO;
230 CDEBUG(D_NET, "incoming MAD successfully processed (status is %d)\n", request->status);
232 complete_sa_request(request);
235 /* MAD send completion */
237 vibnal_mad_sent_cb(gsi_class_handle_t handle, void *context, gsi_dtgrm_t * dtgrm)
239 sa_mad_v2_t *mad = (sa_mad_v2_t *) dtgrm->mad;
241 /* Don't do anything. We might have to resend the datagram later. */
242 CDEBUG(D_NET, "Datagram with TID "LPX64" sent.\n", mad->hdr.transact_id);
246 * method is SUBN_ADM_SET, SUBN_ADM_GET, SUBN_ADM_DELETE. Tables not supported.
247 * nid is the nid to advertize/query/unadvertize
248 * Note: dgid is in network order.
250 static void fill_pathrecord_request(struct sa_request *request, vv_gid_t dgid)
252 gsi_dtgrm_t *dtgrm = request->dtgrm_req;
253 sa_mad_v2_t *mad = (sa_mad_v2_t *) dtgrm->mad;
254 ib_path_record_v2_t *path = (ib_path_record_v2_t *) mad->payload;
256 memset(mad, 0, MAD_BLOCK_SIZE);
260 dtgrm->rlid = kibnal_data.kib_port_attr.port_sma_address_info.sm_lid;
261 dtgrm->sl = kibnal_data.kib_port_attr.port_sma_address_info.service_level;
263 mad->hdr.base_ver = MAD_IB_BASE_VERSION;
264 mad->hdr.class = MAD_CLASS_SUBN_ADM;
265 mad->hdr.class_ver = 2;
266 mad->hdr.m.ms.method = SUBN_ADM_GET;
267 mad->hdr.attrib_id = SA_PATH_RECORD; /* something(?) will swap that field */
268 mad->hdr.attrib_modifier = 0xFFFFFFFF; /* and that one too? */
270 /* Note: the transaction ID is set by the Voltaire stack if it is 0. */
272 /* TODO: these harcoded value to something better */
273 mad->payload_len = cpu_to_be32(0x40 /*header size*/ + 0x35 /* PathRecord size */);
275 mad->component_mask = cpu_to_be64(
276 (1 << 2) | /* DGID */
277 (1 << 3) | /* SGID */
278 (1 << 12)| /* numb_paths*/
279 (1 << 13) /* P_key */
282 path->pkey = cpu_to_be16(kibnal_data.kib_port_pkey);
283 path->sgid = kibnal_data.kib_port_gid;
284 gid_swap(&path->sgid);
285 path->dgid = dgid; /* already in network order */
290 * Do a path record query
291 * If callback is NULL, the function is synchronous (and context is ignored).
292 * Note: dgid is in network order.
294 /* TODO: passing a request is a bit of a hack, but since this function
295 * is called under interrupt, we cannot allocate memory here :(. */
296 int kibnal_pathrecord_op(struct sa_request *request, vv_gid_t dgid, sa_request_cb_t callback, void *context)
300 LASSERT (kibnal_data.kib_nid != PTL_NID_ANY);
302 fill_pathrecord_request(request, dgid);
305 request->callback = callback;
306 request->context = context;
308 init_completion(&request->signal);
311 ret = vibnal_start_sa_request(request);
313 CERROR("vibnal_send_sa failed: %d\n", ret);
314 free_sa_request(request);
317 /* Return. The callback will have to free the SA request. */
320 wait_for_completion(&request->signal);
322 ret = request->status;
325 CERROR ("Error %d in querying a path record\n", ret);
328 free_sa_request(request);