xref: /illumos-gate/usr/src/uts/intel/io/ipmi/ipmi.c (revision 2c76d751)
1989f2807SJerry Jelinek /*
2989f2807SJerry Jelinek  * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
3989f2807SJerry Jelinek  * All rights reserved.
4989f2807SJerry Jelinek  *
5989f2807SJerry Jelinek  * Redistribution and use in source and binary forms, with or without
6989f2807SJerry Jelinek  * modification, are permitted provided that the following conditions
7989f2807SJerry Jelinek  * are met:
8989f2807SJerry Jelinek  * 1. Redistributions of source code must retain the above copyright
9989f2807SJerry Jelinek  *    notice, this list of conditions and the following disclaimer.
10989f2807SJerry Jelinek  * 2. Redistributions in binary form must reproduce the above copyright
11989f2807SJerry Jelinek  *    notice, this list of conditions and the following disclaimer in the
12989f2807SJerry Jelinek  *    documentation and/or other materials provided with the distribution.
13989f2807SJerry Jelinek  *
14989f2807SJerry Jelinek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15989f2807SJerry Jelinek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16989f2807SJerry Jelinek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17989f2807SJerry Jelinek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18989f2807SJerry Jelinek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19989f2807SJerry Jelinek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20989f2807SJerry Jelinek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21989f2807SJerry Jelinek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22989f2807SJerry Jelinek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23989f2807SJerry Jelinek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24989f2807SJerry Jelinek  * SUCH DAMAGE.
25989f2807SJerry Jelinek  */
26989f2807SJerry Jelinek 
27989f2807SJerry Jelinek /* $FreeBSD: src/sys/dev/ipmi/ipmi.c,v 1.16 2011/11/07 15:43:11 ed Exp $ */
28989f2807SJerry Jelinek 
29989f2807SJerry Jelinek /*
30989f2807SJerry Jelinek  * Copyright 2012, Joyent, Inc.  All rights reserved.
311e393477SMarcel Telka  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
32989f2807SJerry Jelinek  */
33989f2807SJerry Jelinek 
34989f2807SJerry Jelinek #include <sys/devops.h>
35989f2807SJerry Jelinek #include <sys/conf.h>
36989f2807SJerry Jelinek #include <sys/modctl.h>
37989f2807SJerry Jelinek #include <sys/types.h>
38989f2807SJerry Jelinek #include <sys/file.h>
39989f2807SJerry Jelinek #include <sys/errno.h>
40989f2807SJerry Jelinek #include <sys/open.h>
41989f2807SJerry Jelinek #include <sys/cred.h>
42989f2807SJerry Jelinek #include <sys/uio.h>
43989f2807SJerry Jelinek #include <sys/stat.h>
44989f2807SJerry Jelinek #include <sys/cmn_err.h>
45989f2807SJerry Jelinek #include <sys/ddi.h>
46989f2807SJerry Jelinek #include <sys/sunddi.h>
47989f2807SJerry Jelinek #include <sys/smbios.h>
48989f2807SJerry Jelinek #include <sys/smbios_impl.h>
49989f2807SJerry Jelinek #include <sys/ipmi.h>
50989f2807SJerry Jelinek #include "ipmivars.h"
51989f2807SJerry Jelinek 
52989f2807SJerry Jelinek /*
53989f2807SJerry Jelinek  * Request management.
54989f2807SJerry Jelinek  */
55989f2807SJerry Jelinek 
56989f2807SJerry Jelinek /* Allocate a new request with request and reply buffers. */
57989f2807SJerry Jelinek struct ipmi_request *
ipmi_alloc_request(struct ipmi_device * dev,long msgid,uint8_t addr,uint8_t command,size_t requestlen,size_t replylen)58989f2807SJerry Jelinek ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr,
59989f2807SJerry Jelinek     uint8_t command, size_t requestlen, size_t replylen)
60989f2807SJerry Jelinek {
61989f2807SJerry Jelinek 	struct ipmi_request *req;
62989f2807SJerry Jelinek 
63989f2807SJerry Jelinek 	req = kmem_zalloc(sizeof (struct ipmi_request) + requestlen + replylen,
64989f2807SJerry Jelinek 	    KM_SLEEP);
65989f2807SJerry Jelinek 	req->ir_sz = sizeof (struct ipmi_request) + requestlen + replylen;
66989f2807SJerry Jelinek 	req->ir_owner = dev;
67989f2807SJerry Jelinek 	req->ir_msgid = msgid;
68989f2807SJerry Jelinek 	req->ir_addr = addr;
69989f2807SJerry Jelinek 	req->ir_command = command;
70989f2807SJerry Jelinek 	if (requestlen) {
71989f2807SJerry Jelinek 		req->ir_request = (uchar_t *)&req[1];
72989f2807SJerry Jelinek 		req->ir_requestlen = requestlen;
73989f2807SJerry Jelinek 	}
74989f2807SJerry Jelinek 	if (replylen) {
75989f2807SJerry Jelinek 		req->ir_reply = (uchar_t *)&req[1] + requestlen;
76989f2807SJerry Jelinek 		req->ir_replybuflen = replylen;
77989f2807SJerry Jelinek 	}
781e393477SMarcel Telka 
791e393477SMarcel Telka 	cv_init(&req->ir_cv, NULL, CV_DEFAULT, NULL);
801e393477SMarcel Telka 	req->ir_status = IRS_ALLOCATED;
811e393477SMarcel Telka 
82989f2807SJerry Jelinek 	return (req);
83989f2807SJerry Jelinek }
84989f2807SJerry Jelinek 
85989f2807SJerry Jelinek /* Free a request no longer in use. */
86989f2807SJerry Jelinek void
ipmi_free_request(struct ipmi_request * req)87989f2807SJerry Jelinek ipmi_free_request(struct ipmi_request *req)
88989f2807SJerry Jelinek {
891e393477SMarcel Telka 	if (req == NULL)
901e393477SMarcel Telka 		return;
911e393477SMarcel Telka 
921e393477SMarcel Telka 	cv_destroy(&req->ir_cv);
931e393477SMarcel Telka 
94989f2807SJerry Jelinek 	kmem_free(req, req->ir_sz);
95989f2807SJerry Jelinek }
96989f2807SJerry Jelinek 
97989f2807SJerry Jelinek /* Store a processed request on the appropriate completion queue. */
98989f2807SJerry Jelinek /*ARGSUSED*/
99989f2807SJerry Jelinek void
ipmi_complete_request(struct ipmi_softc * sc,struct ipmi_request * req)100989f2807SJerry Jelinek ipmi_complete_request(struct ipmi_softc *sc, struct ipmi_request *req)
101989f2807SJerry Jelinek {
102989f2807SJerry Jelinek 	struct ipmi_device *dev;
103989f2807SJerry Jelinek 
104989f2807SJerry Jelinek 	IPMI_LOCK_ASSERT(sc);
105989f2807SJerry Jelinek 
1061e393477SMarcel Telka 	if (req->ir_status == IRS_CANCELED) {
1071e393477SMarcel Telka 		ASSERT(req->ir_owner == NULL);
1081e393477SMarcel Telka 		ipmi_free_request(req);
1091e393477SMarcel Telka 		return;
1101e393477SMarcel Telka 	}
111cc944374SMarcel Telka 
1121e393477SMarcel Telka 	req->ir_status = IRS_COMPLETED;
1131e393477SMarcel Telka 
114cc944374SMarcel Telka 	/*
115cc944374SMarcel Telka 	 * Anonymous requests (from inside the driver) always have a
116cc944374SMarcel Telka 	 * waiter that we awaken.
117cc944374SMarcel Telka 	 */
118cc944374SMarcel Telka 	if (req->ir_owner == NULL) {
119cc944374SMarcel Telka 		cv_signal(&req->ir_cv);
120cc944374SMarcel Telka 	} else {
121989f2807SJerry Jelinek 		dev = req->ir_owner;
122989f2807SJerry Jelinek 		TAILQ_INSERT_TAIL(&dev->ipmi_completed_requests, req, ir_link);
123*2c76d751SPatrick Mooney 		pollwakeup(&dev->ipmi_pollhead, POLLIN | POLLRDNORM);
124cc944374SMarcel Telka 
125cc944374SMarcel Telka 		dev->ipmi_status &= ~IPMI_BUSY;
126cc944374SMarcel Telka 		if (dev->ipmi_status & IPMI_CLOSING)
127cc944374SMarcel Telka 			cv_signal(&dev->ipmi_cv);
128989f2807SJerry Jelinek 	}
129989f2807SJerry Jelinek }
130989f2807SJerry Jelinek 
131989f2807SJerry Jelinek /*
132989f2807SJerry Jelinek  * Enqueue an internal driver request and wait until it is completed.
133989f2807SJerry Jelinek  */
134989f2807SJerry Jelinek static int
ipmi_submit_driver_request(struct ipmi_softc * sc,struct ipmi_request ** preq,int timo)1351e393477SMarcel Telka ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request **preq,
136989f2807SJerry Jelinek     int timo)
137989f2807SJerry Jelinek {
138989f2807SJerry Jelinek 	int error;
1391e393477SMarcel Telka 	struct ipmi_request *req = *preq;
1401e393477SMarcel Telka 
1411e393477SMarcel Telka 	ASSERT(req->ir_owner == NULL);
142989f2807SJerry Jelinek 
143989f2807SJerry Jelinek 	IPMI_LOCK(sc);
144989f2807SJerry Jelinek 	error = sc->ipmi_enqueue_request(sc, req);
1451e393477SMarcel Telka 
1461e393477SMarcel Telka 	if (error != 0) {
147989f2807SJerry Jelinek 		IPMI_UNLOCK(sc);
1481e393477SMarcel Telka 		return (error);
1491e393477SMarcel Telka 	}
1501e393477SMarcel Telka 
1511e393477SMarcel Telka 	while (req->ir_status != IRS_COMPLETED && error >= 0)
152989f2807SJerry Jelinek 		if (timo == 0)
1531e393477SMarcel Telka 			cv_wait(&req->ir_cv, &sc->ipmi_lock);
154989f2807SJerry Jelinek 		else
1551e393477SMarcel Telka 			error = cv_timedwait(&req->ir_cv, &sc->ipmi_lock,
156989f2807SJerry Jelinek 			    ddi_get_lbolt() + timo);
1571e393477SMarcel Telka 
1581e393477SMarcel Telka 	switch (req->ir_status) {
1591e393477SMarcel Telka 		case IRS_QUEUED:
1601e393477SMarcel Telka 			TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
1611e393477SMarcel Telka 			req->ir_status = IRS_CANCELED;
162989f2807SJerry Jelinek 			error = EWOULDBLOCK;
1631e393477SMarcel Telka 			break;
1641e393477SMarcel Telka 		case IRS_PROCESSED:
1651e393477SMarcel Telka 			req->ir_status = IRS_CANCELED;
1661e393477SMarcel Telka 			error = EWOULDBLOCK;
1671e393477SMarcel Telka 			*preq = NULL;
1681e393477SMarcel Telka 			break;
1691e393477SMarcel Telka 		case IRS_COMPLETED:
170989f2807SJerry Jelinek 			error = req->ir_error;
1711e393477SMarcel Telka 			break;
1721e393477SMarcel Telka 		default:
1731e393477SMarcel Telka 			panic("IPMI: Invalid request status");
1741e393477SMarcel Telka 			break;
175989f2807SJerry Jelinek 	}
176989f2807SJerry Jelinek 	IPMI_UNLOCK(sc);
177989f2807SJerry Jelinek 
178989f2807SJerry Jelinek 	return (error);
179989f2807SJerry Jelinek }
180989f2807SJerry Jelinek 
181989f2807SJerry Jelinek /*
182989f2807SJerry Jelinek  * Helper routine for polled system interfaces that use
183989f2807SJerry Jelinek  * ipmi_polled_enqueue_request() to queue requests.  This request
184989f2807SJerry Jelinek  * waits until there is a pending request and then returns the first
185989f2807SJerry Jelinek  * request.  If the driver is shutting down, it returns NULL.
186989f2807SJerry Jelinek  */
187989f2807SJerry Jelinek struct ipmi_request *
ipmi_dequeue_request(struct ipmi_softc * sc)188989f2807SJerry Jelinek ipmi_dequeue_request(struct ipmi_softc *sc)
189989f2807SJerry Jelinek {
190989f2807SJerry Jelinek 	struct ipmi_request *req;
191989f2807SJerry Jelinek 
192989f2807SJerry Jelinek 	IPMI_LOCK_ASSERT(sc);
193989f2807SJerry Jelinek 
194989f2807SJerry Jelinek 	while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests))
195989f2807SJerry Jelinek 		cv_wait(&sc->ipmi_request_added, &sc->ipmi_lock);
196989f2807SJerry Jelinek 	if (sc->ipmi_detaching)
197989f2807SJerry Jelinek 		return (NULL);
198989f2807SJerry Jelinek 
199989f2807SJerry Jelinek 	req = TAILQ_FIRST(&sc->ipmi_pending_requests);
200989f2807SJerry Jelinek 	TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
2011e393477SMarcel Telka 	req->ir_status = IRS_PROCESSED;
202cc944374SMarcel Telka 
203cc944374SMarcel Telka 	if (req->ir_owner != NULL)
204cc944374SMarcel Telka 		req->ir_owner->ipmi_status |= IPMI_BUSY;
205cc944374SMarcel Telka 
206989f2807SJerry Jelinek 	return (req);
207989f2807SJerry Jelinek }
208989f2807SJerry Jelinek 
209989f2807SJerry Jelinek int
ipmi_polled_enqueue_request(struct ipmi_softc * sc,struct ipmi_request * req)210989f2807SJerry Jelinek ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req)
211989f2807SJerry Jelinek {
212989f2807SJerry Jelinek 
213989f2807SJerry Jelinek 	IPMI_LOCK_ASSERT(sc);
214989f2807SJerry Jelinek 
215989f2807SJerry Jelinek 	TAILQ_INSERT_TAIL(&sc->ipmi_pending_requests, req, ir_link);
2161e393477SMarcel Telka 	req->ir_status = IRS_QUEUED;
217989f2807SJerry Jelinek 	cv_signal(&sc->ipmi_request_added);
218989f2807SJerry Jelinek 	return (0);
219989f2807SJerry Jelinek }
220989f2807SJerry Jelinek 
221989f2807SJerry Jelinek void
ipmi_shutdown(struct ipmi_softc * sc)222e1c99a74SAlek Pinchuk ipmi_shutdown(struct ipmi_softc *sc)
223e1c99a74SAlek Pinchuk {
224e1c99a74SAlek Pinchuk 	taskq_destroy(sc->ipmi_kthread);
225e1c99a74SAlek Pinchuk 
226e1c99a74SAlek Pinchuk 	cv_destroy(&sc->ipmi_request_added);
227e1c99a74SAlek Pinchuk 	mutex_destroy(&sc->ipmi_lock);
228e1c99a74SAlek Pinchuk }
229e1c99a74SAlek Pinchuk 
230e1c99a74SAlek Pinchuk boolean_t
ipmi_startup(struct ipmi_softc * sc)231989f2807SJerry Jelinek ipmi_startup(struct ipmi_softc *sc)
232989f2807SJerry Jelinek {
233989f2807SJerry Jelinek 	struct ipmi_request *req;
234989f2807SJerry Jelinek 	int error, i;
235989f2807SJerry Jelinek 
236989f2807SJerry Jelinek 	/* Initialize interface-independent state. */
237989f2807SJerry Jelinek 	mutex_init(&sc->ipmi_lock, NULL, MUTEX_DEFAULT, NULL);
238989f2807SJerry Jelinek 	cv_init(&sc->ipmi_request_added, NULL, CV_DEFAULT, NULL);
239989f2807SJerry Jelinek 	TAILQ_INIT(&sc->ipmi_pending_requests);
240989f2807SJerry Jelinek 
241989f2807SJerry Jelinek 	/* Initialize interface-dependent state. */
242989f2807SJerry Jelinek 	error = sc->ipmi_startup(sc);
243989f2807SJerry Jelinek 	if (error) {
244989f2807SJerry Jelinek 		cmn_err(CE_WARN, "Failed to initialize interface: %d", error);
245e1c99a74SAlek Pinchuk 		return (B_FALSE);
246989f2807SJerry Jelinek 	}
247989f2807SJerry Jelinek 
248989f2807SJerry Jelinek 	/* Send a GET_DEVICE_ID request. */
249989f2807SJerry Jelinek 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
250989f2807SJerry Jelinek 	    IPMI_GET_DEVICE_ID, 0, 15);
251989f2807SJerry Jelinek 
2521e393477SMarcel Telka 	error = ipmi_submit_driver_request(sc, &req, MAX_TIMEOUT);
253989f2807SJerry Jelinek 	if (error == EWOULDBLOCK) {
254989f2807SJerry Jelinek 		cmn_err(CE_WARN, "Timed out waiting for GET_DEVICE_ID");
255989f2807SJerry Jelinek 		ipmi_free_request(req);
256e1c99a74SAlek Pinchuk 		return (B_FALSE);
257989f2807SJerry Jelinek 	} else if (error) {
258989f2807SJerry Jelinek 		cmn_err(CE_WARN, "Failed GET_DEVICE_ID: %d", error);
259989f2807SJerry Jelinek 		ipmi_free_request(req);
260e1c99a74SAlek Pinchuk 		return (B_FALSE);
261989f2807SJerry Jelinek 	} else if (req->ir_compcode != 0) {
262989f2807SJerry Jelinek 		cmn_err(CE_WARN,
263989f2807SJerry Jelinek 		    "Bad completion code for GET_DEVICE_ID: %d",
264989f2807SJerry Jelinek 		    req->ir_compcode);
265989f2807SJerry Jelinek 		ipmi_free_request(req);
266e1c99a74SAlek Pinchuk 		return (B_FALSE);
267989f2807SJerry Jelinek 	} else if (req->ir_replylen < 5) {
268989f2807SJerry Jelinek 		cmn_err(CE_WARN, "Short reply for GET_DEVICE_ID: %d",
269989f2807SJerry Jelinek 		    req->ir_replylen);
270989f2807SJerry Jelinek 		ipmi_free_request(req);
271e1c99a74SAlek Pinchuk 		return (B_FALSE);
272989f2807SJerry Jelinek 	}
273989f2807SJerry Jelinek 
274989f2807SJerry Jelinek 	cmn_err(CE_CONT, "!device rev. %d, firmware rev. %d.%d%d, "
275989f2807SJerry Jelinek 	    "version %d.%d",
276989f2807SJerry Jelinek 	    req->ir_reply[1] & 0x0f, req->ir_reply[2] & 0x7f,
277989f2807SJerry Jelinek 	    req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f,
278989f2807SJerry Jelinek 	    req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4);
279989f2807SJerry Jelinek 
280989f2807SJerry Jelinek 	ipmi_free_request(req);
281989f2807SJerry Jelinek 
282989f2807SJerry Jelinek 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
283989f2807SJerry Jelinek 	    IPMI_CLEAR_FLAGS, 1, 0);
284989f2807SJerry Jelinek 
2851e393477SMarcel Telka 	if ((error = ipmi_submit_driver_request(sc, &req, 0)) != 0) {
286989f2807SJerry Jelinek 		cmn_err(CE_WARN, "Failed to clear IPMI flags: %d\n", error);
287e1c99a74SAlek Pinchuk 		ipmi_free_request(req);
288e1c99a74SAlek Pinchuk 		return (B_FALSE);
289e1c99a74SAlek Pinchuk 	}
290989f2807SJerry Jelinek 
291989f2807SJerry Jelinek 	/* Magic numbers */
292989f2807SJerry Jelinek 	if (req->ir_compcode == 0xc0) {
293989f2807SJerry Jelinek 		cmn_err(CE_NOTE, "!Clear flags is busy");
294989f2807SJerry Jelinek 	}
295989f2807SJerry Jelinek 	if (req->ir_compcode == 0xc1) {
296989f2807SJerry Jelinek 		cmn_err(CE_NOTE, "!Clear flags illegal");
297989f2807SJerry Jelinek 	}
298989f2807SJerry Jelinek 	ipmi_free_request(req);
299989f2807SJerry Jelinek 
300989f2807SJerry Jelinek 	for (i = 0; i < 8; i++) {
301989f2807SJerry Jelinek 		req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
302989f2807SJerry Jelinek 		    IPMI_GET_CHANNEL_INFO, 1, 0);
303989f2807SJerry Jelinek 		req->ir_request[0] = (uchar_t)i;
304989f2807SJerry Jelinek 
3051e393477SMarcel Telka 		if (ipmi_submit_driver_request(sc, &req, 0) != 0) {
306989f2807SJerry Jelinek 			ipmi_free_request(req);
307989f2807SJerry Jelinek 			break;
308989f2807SJerry Jelinek 		}
309989f2807SJerry Jelinek 
310989f2807SJerry Jelinek 		if (req->ir_compcode != 0) {
311989f2807SJerry Jelinek 			ipmi_free_request(req);
312989f2807SJerry Jelinek 			break;
313989f2807SJerry Jelinek 		}
314989f2807SJerry Jelinek 		ipmi_free_request(req);
315989f2807SJerry Jelinek 	}
316989f2807SJerry Jelinek 	cmn_err(CE_CONT, "!number of channels %d", i);
317989f2807SJerry Jelinek 
318989f2807SJerry Jelinek 	/* probe for watchdog */
319989f2807SJerry Jelinek 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
320989f2807SJerry Jelinek 	    IPMI_GET_WDOG, 0, 0);
321989f2807SJerry Jelinek 
3221e393477SMarcel Telka 	if ((error = ipmi_submit_driver_request(sc, &req, 0)) != 0) {
323989f2807SJerry Jelinek 		cmn_err(CE_WARN, "Failed to check IPMI watchdog: %d\n", error);
324989f2807SJerry Jelinek 		ipmi_free_request(req);
325e1c99a74SAlek Pinchuk 		return (B_FALSE);
326989f2807SJerry Jelinek 	}
327989f2807SJerry Jelinek 
328989f2807SJerry Jelinek 	if (req->ir_compcode == 0x00) {
329989f2807SJerry Jelinek 		cmn_err(CE_CONT, "!watchdog supported");
330989f2807SJerry Jelinek 
331989f2807SJerry Jelinek 		/*
332989f2807SJerry Jelinek 		 * Here is where we could register a watchdog event handler.
333989f2807SJerry Jelinek 		 * See ipmi_wd_event() in the FreeBSD code.
334989f2807SJerry Jelinek 		 */
335989f2807SJerry Jelinek 	}
336989f2807SJerry Jelinek 	ipmi_free_request(req);
337e1c99a74SAlek Pinchuk 
338e1c99a74SAlek Pinchuk 	return (B_TRUE);
339989f2807SJerry Jelinek }
340