xref: /dflybsd-src/sys/dev/misc/ipmi/ipmi_ssif.c (revision 53a374c18f69009d375e6a59247b55bfe03f59e2)
1*53a374c1SSascha Wildner /*-
2*53a374c1SSascha Wildner  * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
3*53a374c1SSascha Wildner  * All rights reserved.
4*53a374c1SSascha Wildner  *
5*53a374c1SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6*53a374c1SSascha Wildner  * modification, are permitted provided that the following conditions
7*53a374c1SSascha Wildner  * are met:
8*53a374c1SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9*53a374c1SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10*53a374c1SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11*53a374c1SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12*53a374c1SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13*53a374c1SSascha Wildner  *
14*53a374c1SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*53a374c1SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*53a374c1SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*53a374c1SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*53a374c1SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*53a374c1SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*53a374c1SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*53a374c1SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*53a374c1SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*53a374c1SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*53a374c1SSascha Wildner  * SUCH DAMAGE.
25*53a374c1SSascha Wildner  *
26*53a374c1SSascha Wildner  * $FreeBSD: head/sys/dev/ipmi/ipmi_ssif.c 172836 2007-10-20 23:23:23Z julian $
27*53a374c1SSascha Wildner  */
28*53a374c1SSascha Wildner 
29*53a374c1SSascha Wildner #include <sys/param.h>
30*53a374c1SSascha Wildner #include <sys/systm.h>
31*53a374c1SSascha Wildner #include <sys/bus.h>
32*53a374c1SSascha Wildner #include <sys/condvar.h>
33*53a374c1SSascha Wildner #include <sys/eventhandler.h>
34*53a374c1SSascha Wildner #include <sys/kernel.h>
35*53a374c1SSascha Wildner #include <sys/kthread.h>
36*53a374c1SSascha Wildner #include <sys/module.h>
37*53a374c1SSascha Wildner #include <sys/conf.h>
38*53a374c1SSascha Wildner 
39*53a374c1SSascha Wildner #include <bus/smbus/smbconf.h>
40*53a374c1SSascha Wildner #include <dev/smbus/smb/smb.h>
41*53a374c1SSascha Wildner 
42*53a374c1SSascha Wildner #include "smbus_if.h"
43*53a374c1SSascha Wildner 
44*53a374c1SSascha Wildner #ifdef LOCAL_MODULE
45*53a374c1SSascha Wildner #include <ipmivars.h>
46*53a374c1SSascha Wildner #else
47*53a374c1SSascha Wildner #include <dev/misc/ipmi/ipmivars.h>
48*53a374c1SSascha Wildner #endif
49*53a374c1SSascha Wildner 
50*53a374c1SSascha Wildner #define SMBUS_WRITE_SINGLE	0x02
51*53a374c1SSascha Wildner #define SMBUS_WRITE_START	0x06
52*53a374c1SSascha Wildner #define SMBUS_WRITE_CONT	0x07
53*53a374c1SSascha Wildner #define SMBUS_READ_START	0x03
54*53a374c1SSascha Wildner #define SMBUS_READ_CONT		0x09
55*53a374c1SSascha Wildner #define SMBUS_DATA_SIZE		32
56*53a374c1SSascha Wildner 
57*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
58*53a374c1SSascha Wildner static void
dump_buffer(device_t dev,const char * msg,u_char * bytes,int len)59*53a374c1SSascha Wildner dump_buffer(device_t dev, const char *msg, u_char *bytes, int len)
60*53a374c1SSascha Wildner {
61*53a374c1SSascha Wildner 	int i;
62*53a374c1SSascha Wildner 
63*53a374c1SSascha Wildner 	device_printf(dev, "%s:", msg);
64*53a374c1SSascha Wildner 	for (i = 0; i < len; i++)
65*53a374c1SSascha Wildner 		kprintf(" %02x", bytes[i]);
66*53a374c1SSascha Wildner 	kprintf("\n");
67*53a374c1SSascha Wildner }
68*53a374c1SSascha Wildner #endif
69*53a374c1SSascha Wildner 
70*53a374c1SSascha Wildner static int
ssif_polled_request(struct ipmi_softc * sc,struct ipmi_request * req)71*53a374c1SSascha Wildner ssif_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
72*53a374c1SSascha Wildner {
73*53a374c1SSascha Wildner 	u_char ssif_buf[SMBUS_DATA_SIZE];
74*53a374c1SSascha Wildner 	device_t dev = sc->ipmi_dev;
75*53a374c1SSascha Wildner 	device_t smbus = sc->ipmi_ssif_smbus;
76*53a374c1SSascha Wildner 	u_char *cp, block, count, offset;
77*53a374c1SSascha Wildner 	size_t len;
78*53a374c1SSascha Wildner 	int error;
79*53a374c1SSascha Wildner 
80*53a374c1SSascha Wildner 	/* Acquire the bus while we send the request. */
81*53a374c1SSascha Wildner 	if (smbus_request_bus(smbus, dev, SMB_WAIT) != 0)
82*53a374c1SSascha Wildner 		return (0);
83*53a374c1SSascha Wildner 
84*53a374c1SSascha Wildner 	/*
85*53a374c1SSascha Wildner 	 * First, send out the request.  Begin by filling out the first
86*53a374c1SSascha Wildner 	 * packet which includes the NetFn/LUN and command.
87*53a374c1SSascha Wildner 	 */
88*53a374c1SSascha Wildner 	ssif_buf[0] = req->ir_addr;
89*53a374c1SSascha Wildner 	ssif_buf[1] = req->ir_command;
90*53a374c1SSascha Wildner 	if (req->ir_requestlen > 0)
91*53a374c1SSascha Wildner 		bcopy(req->ir_request, &ssif_buf[2],
92*53a374c1SSascha Wildner 		    min(req->ir_requestlen, SMBUS_DATA_SIZE - 2));
93*53a374c1SSascha Wildner 
94*53a374c1SSascha Wildner 	/* Small requests are sent with a single command. */
95*53a374c1SSascha Wildner 	if (req->ir_requestlen <= 30) {
96*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
97*53a374c1SSascha Wildner 		dump_buffer(dev, "WRITE_SINGLE", ssif_buf,
98*53a374c1SSascha Wildner 		    req->ir_requestlen + 2);
99*53a374c1SSascha Wildner #endif
100*53a374c1SSascha Wildner 		error = smbus_error(smbus_bwrite(smbus,
101*53a374c1SSascha Wildner 			sc->ipmi_ssif_smbus_address, SMBUS_WRITE_SINGLE,
102*53a374c1SSascha Wildner 			req->ir_requestlen + 2, ssif_buf));
103*53a374c1SSascha Wildner 		if (error) {
104*53a374c1SSascha Wildner #ifdef SSIF_ERROR_DEBUG
105*53a374c1SSascha Wildner 			device_printf(dev, "SSIF: WRITE_SINGLE error %d\n",
106*53a374c1SSascha Wildner 			    error);
107*53a374c1SSascha Wildner #endif
108*53a374c1SSascha Wildner 			goto fail;
109*53a374c1SSascha Wildner 		}
110*53a374c1SSascha Wildner 	} else {
111*53a374c1SSascha Wildner 		/* Longer requests are sent out in 32-byte messages. */
112*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
113*53a374c1SSascha Wildner 		dump_buffer(dev, "WRITE_START", ssif_buf, SMBUS_DATA_SIZE);
114*53a374c1SSascha Wildner #endif
115*53a374c1SSascha Wildner 		error = smbus_error(smbus_bwrite(smbus,
116*53a374c1SSascha Wildner 			sc->ipmi_ssif_smbus_address, SMBUS_WRITE_START,
117*53a374c1SSascha Wildner 			SMBUS_DATA_SIZE, ssif_buf));
118*53a374c1SSascha Wildner 		if (error) {
119*53a374c1SSascha Wildner #ifdef SSIF_ERROR_DEBUG
120*53a374c1SSascha Wildner 			device_printf(dev, "SSIF: WRITE_START error %d\n",
121*53a374c1SSascha Wildner 			    error);
122*53a374c1SSascha Wildner #endif
123*53a374c1SSascha Wildner 			goto fail;
124*53a374c1SSascha Wildner 		}
125*53a374c1SSascha Wildner 
126*53a374c1SSascha Wildner 		len = req->ir_requestlen - (SMBUS_DATA_SIZE - 2);
127*53a374c1SSascha Wildner 		cp = req->ir_request + (SMBUS_DATA_SIZE - 2);
128*53a374c1SSascha Wildner 		while (len > 0) {
129*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
130*53a374c1SSascha Wildner 			dump_buffer(dev, "WRITE_CONT", cp,
131*53a374c1SSascha Wildner 			    min(len, SMBUS_DATA_SIZE));
132*53a374c1SSascha Wildner #endif
133*53a374c1SSascha Wildner 			error = smbus_error(smbus_bwrite(smbus,
134*53a374c1SSascha Wildner 			    sc->ipmi_ssif_smbus_address, SMBUS_WRITE_CONT,
135*53a374c1SSascha Wildner 			    min(len, SMBUS_DATA_SIZE), cp));
136*53a374c1SSascha Wildner 			if (error) {
137*53a374c1SSascha Wildner #ifdef SSIF_ERROR_DEBUG
138*53a374c1SSascha Wildner 				device_printf(dev, "SSIF: WRITE_CONT error %d\n",
139*53a374c1SSascha Wildner 				    error);
140*53a374c1SSascha Wildner #endif
141*53a374c1SSascha Wildner 				goto fail;
142*53a374c1SSascha Wildner 			}
143*53a374c1SSascha Wildner 			cp += SMBUS_DATA_SIZE;
144*53a374c1SSascha Wildner 			len -= SMBUS_DATA_SIZE;
145*53a374c1SSascha Wildner 		}
146*53a374c1SSascha Wildner 
147*53a374c1SSascha Wildner 		/*
148*53a374c1SSascha Wildner 		 * The final WRITE_CONT transaction has to have a non-zero
149*53a374c1SSascha Wildner 		 * length that is also not SMBUS_DATA_SIZE.  If our last
150*53a374c1SSascha Wildner 		 * WRITE_CONT transaction in the loop sent SMBUS_DATA_SIZE
151*53a374c1SSascha Wildner 		 * bytes, then len will be 0, and we send an extra 0x00 byte
152*53a374c1SSascha Wildner 		 * to terminate the transaction.
153*53a374c1SSascha Wildner 		 */
154*53a374c1SSascha Wildner 		if (len == 0) {
155*53a374c1SSascha Wildner 			char c = 0;
156*53a374c1SSascha Wildner 
157*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
158*53a374c1SSascha Wildner 			dump_buffer(dev, "WRITE_CONT", &c, 1);
159*53a374c1SSascha Wildner #endif
160*53a374c1SSascha Wildner 			error = smbus_error(smbus_bwrite(smbus,
161*53a374c1SSascha Wildner 				sc->ipmi_ssif_smbus_address, SMBUS_WRITE_CONT,
162*53a374c1SSascha Wildner 				1, &c));
163*53a374c1SSascha Wildner 			if (error) {
164*53a374c1SSascha Wildner #ifdef SSIF_ERROR_DEBUG
165*53a374c1SSascha Wildner 				device_printf(dev, "SSIF: WRITE_CONT error %d\n",
166*53a374c1SSascha Wildner 				    error);
167*53a374c1SSascha Wildner #endif
168*53a374c1SSascha Wildner 				goto fail;
169*53a374c1SSascha Wildner 			}
170*53a374c1SSascha Wildner 		}
171*53a374c1SSascha Wildner 	}
172*53a374c1SSascha Wildner 
173*53a374c1SSascha Wildner 	/* Release the bus. */
174*53a374c1SSascha Wildner 	smbus_release_bus(smbus, dev);
175*53a374c1SSascha Wildner 
176*53a374c1SSascha Wildner 	/* Give the BMC 100ms to chew on the request. */
177*53a374c1SSascha Wildner 	tsleep(ssif_polled_request, 0, "ssifwt", hz / 10);
178*53a374c1SSascha Wildner 
179*53a374c1SSascha Wildner 	/* Try to read the first packet. */
180*53a374c1SSascha Wildner read_start:
181*53a374c1SSascha Wildner 	if (smbus_request_bus(smbus, dev, SMB_WAIT) != 0)
182*53a374c1SSascha Wildner 		return (0);
183*53a374c1SSascha Wildner 	count = SMBUS_DATA_SIZE;
184*53a374c1SSascha Wildner 	error = smbus_error(smbus_bread(smbus,
185*53a374c1SSascha Wildner 	    sc->ipmi_ssif_smbus_address, SMBUS_READ_START, &count, ssif_buf));
186*53a374c1SSascha Wildner 	if (error == ENXIO || error == EBUSY) {
187*53a374c1SSascha Wildner 		smbus_release_bus(smbus, dev);
188*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
189*53a374c1SSascha Wildner 		device_printf(dev, "SSIF: READ_START retry\n");
190*53a374c1SSascha Wildner #endif
191*53a374c1SSascha Wildner 		/* Give the BMC another 10ms. */
192*53a374c1SSascha Wildner 		tsleep(ssif_polled_request, 0, "ssifwt", hz / 100);
193*53a374c1SSascha Wildner 		goto read_start;
194*53a374c1SSascha Wildner 	}
195*53a374c1SSascha Wildner 	if (error) {
196*53a374c1SSascha Wildner #ifdef SSIF_ERROR_DEBUG
197*53a374c1SSascha Wildner 		device_printf(dev, "SSIF: READ_START failed: %d\n", error);
198*53a374c1SSascha Wildner #endif
199*53a374c1SSascha Wildner 		goto fail;
200*53a374c1SSascha Wildner 	}
201*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
202*53a374c1SSascha Wildner 	device_printf(dev, "SSIF: READ_START: ok\n");
203*53a374c1SSascha Wildner #endif
204*53a374c1SSascha Wildner 
205*53a374c1SSascha Wildner 	/*
206*53a374c1SSascha Wildner 	 * If this is the first part of a multi-part read, then we need to
207*53a374c1SSascha Wildner 	 * skip the first two bytes.
208*53a374c1SSascha Wildner 	 */
209*53a374c1SSascha Wildner 	if (count == SMBUS_DATA_SIZE && ssif_buf[0] == 0 && ssif_buf[1] == 1)
210*53a374c1SSascha Wildner 		offset = 2;
211*53a374c1SSascha Wildner 	else
212*53a374c1SSascha Wildner 		offset = 0;
213*53a374c1SSascha Wildner 
214*53a374c1SSascha Wildner 	/* We had better get the reply header. */
215*53a374c1SSascha Wildner 	if (count < 3) {
216*53a374c1SSascha Wildner 		device_printf(dev, "SSIF: Short reply packet\n");
217*53a374c1SSascha Wildner 		goto fail;
218*53a374c1SSascha Wildner 	}
219*53a374c1SSascha Wildner 
220*53a374c1SSascha Wildner 	/* Verify the NetFn/LUN. */
221*53a374c1SSascha Wildner 	if (ssif_buf[offset] != IPMI_REPLY_ADDR(req->ir_addr)) {
222*53a374c1SSascha Wildner 		device_printf(dev, "SSIF: Reply address mismatch\n");
223*53a374c1SSascha Wildner 		goto fail;
224*53a374c1SSascha Wildner 	}
225*53a374c1SSascha Wildner 
226*53a374c1SSascha Wildner 	/* Verify the command. */
227*53a374c1SSascha Wildner 	if (ssif_buf[offset + 1] != req->ir_command) {
228*53a374c1SSascha Wildner 		device_printf(dev, "SMIC: Command mismatch\n");
229*53a374c1SSascha Wildner 		goto fail;
230*53a374c1SSascha Wildner 	}
231*53a374c1SSascha Wildner 
232*53a374c1SSascha Wildner 	/* Read the completion code. */
233*53a374c1SSascha Wildner 	req->ir_compcode = ssif_buf[offset + 2];
234*53a374c1SSascha Wildner 
235*53a374c1SSascha Wildner 	/* If this is a single read, just copy the data and return. */
236*53a374c1SSascha Wildner 	if (offset == 0) {
237*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
238*53a374c1SSascha Wildner 		dump_buffer(dev, "READ_SINGLE", ssif_buf, count);
239*53a374c1SSascha Wildner #endif
240*53a374c1SSascha Wildner 		len = count - 3;
241*53a374c1SSascha Wildner 		bcopy(&ssif_buf[3], req->ir_reply,
242*53a374c1SSascha Wildner 		    min(req->ir_replybuflen, len));
243*53a374c1SSascha Wildner 		goto done;
244*53a374c1SSascha Wildner 	}
245*53a374c1SSascha Wildner 
246*53a374c1SSascha Wildner 	/*
247*53a374c1SSascha Wildner 	 * This is the first part of a multi-read transaction, so copy
248*53a374c1SSascha Wildner 	 * out the payload and start looping.
249*53a374c1SSascha Wildner 	 */
250*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
251*53a374c1SSascha Wildner 	dump_buffer(dev, "READ_START", ssif_buf + 2, count - 2);
252*53a374c1SSascha Wildner #endif
253*53a374c1SSascha Wildner 	bcopy(&ssif_buf[5], req->ir_reply, min(req->ir_replybuflen, count - 5));
254*53a374c1SSascha Wildner 	len = count - 5;
255*53a374c1SSascha Wildner 	block = 1;
256*53a374c1SSascha Wildner 
257*53a374c1SSascha Wildner 	for (;;) {
258*53a374c1SSascha Wildner 		/* Read another packet via READ_CONT. */
259*53a374c1SSascha Wildner 		count = SMBUS_DATA_SIZE;
260*53a374c1SSascha Wildner 		error = smbus_error(smbus_bread(smbus,
261*53a374c1SSascha Wildner 		    sc->ipmi_ssif_smbus_address, SMBUS_READ_CONT, &count,
262*53a374c1SSascha Wildner 		    ssif_buf));
263*53a374c1SSascha Wildner 		if (error) {
264*53a374c1SSascha Wildner #ifdef SSIF_ERROR_DEBUG
265*53a374c1SSascha Wildner 			kprintf("SSIF: READ_CONT failed: %d\n", error);
266*53a374c1SSascha Wildner #endif
267*53a374c1SSascha Wildner 			goto fail;
268*53a374c1SSascha Wildner 		}
269*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
270*53a374c1SSascha Wildner 		device_printf(dev, "SSIF: READ_CONT... ok\n");
271*53a374c1SSascha Wildner #endif
272*53a374c1SSascha Wildner 
273*53a374c1SSascha Wildner 		/* Verify the block number.  0xff marks the last block. */
274*53a374c1SSascha Wildner 		if (ssif_buf[0] != 0xff && ssif_buf[0] != block) {
275*53a374c1SSascha Wildner 			device_printf(dev, "SSIF: Read wrong block %d %d\n",
276*53a374c1SSascha Wildner 			    ssif_buf[0], block);
277*53a374c1SSascha Wildner 			goto fail;
278*53a374c1SSascha Wildner 		}
279*53a374c1SSascha Wildner 		if (ssif_buf[0] != 0xff && count < SMBUS_DATA_SIZE) {
280*53a374c1SSascha Wildner 			device_printf(dev,
281*53a374c1SSascha Wildner 			    "SSIF: Read short middle block, length %d\n",
282*53a374c1SSascha Wildner 			    count);
283*53a374c1SSascha Wildner 			goto fail;
284*53a374c1SSascha Wildner 		}
285*53a374c1SSascha Wildner #ifdef SSIF_DEBUG
286*53a374c1SSascha Wildner 		if (ssif_buf[0] == 0xff)
287*53a374c1SSascha Wildner 			dump_buffer(dev, "READ_END", ssif_buf + 1, count - 1);
288*53a374c1SSascha Wildner 		else
289*53a374c1SSascha Wildner 			dump_buffer(dev, "READ_CONT", ssif_buf + 1, count - 1);
290*53a374c1SSascha Wildner #endif
291*53a374c1SSascha Wildner 		if (len < req->ir_replybuflen)
292*53a374c1SSascha Wildner 			bcopy(&ssif_buf[1], &req->ir_reply[len],
293*53a374c1SSascha Wildner 			    min(req->ir_replybuflen - len, count - 1));
294*53a374c1SSascha Wildner 		len += count - 1;
295*53a374c1SSascha Wildner 
296*53a374c1SSascha Wildner 		/* If this was the last block we are done. */
297*53a374c1SSascha Wildner 		if (ssif_buf[0] != 0xff)
298*53a374c1SSascha Wildner 			break;
299*53a374c1SSascha Wildner 		block++;
300*53a374c1SSascha Wildner 	}
301*53a374c1SSascha Wildner 
302*53a374c1SSascha Wildner done:
303*53a374c1SSascha Wildner 	/* Save the total length and return success. */
304*53a374c1SSascha Wildner 	req->ir_replylen = len;
305*53a374c1SSascha Wildner 	smbus_release_bus(smbus, dev);
306*53a374c1SSascha Wildner 	return (1);
307*53a374c1SSascha Wildner 
308*53a374c1SSascha Wildner fail:
309*53a374c1SSascha Wildner 	smbus_release_bus(smbus, dev);
310*53a374c1SSascha Wildner 	return (0);
311*53a374c1SSascha Wildner }
312*53a374c1SSascha Wildner 
313*53a374c1SSascha Wildner static void
ssif_loop(void * arg)314*53a374c1SSascha Wildner ssif_loop(void *arg)
315*53a374c1SSascha Wildner {
316*53a374c1SSascha Wildner 	struct ipmi_softc *sc = arg;
317*53a374c1SSascha Wildner 	struct ipmi_request *req;
318*53a374c1SSascha Wildner 	int i, ok;
319*53a374c1SSascha Wildner 
320*53a374c1SSascha Wildner 	IPMI_LOCK(sc);
321*53a374c1SSascha Wildner 	while ((req = ipmi_dequeue_request(sc)) != NULL) {
322*53a374c1SSascha Wildner 		IPMI_UNLOCK(sc);
323*53a374c1SSascha Wildner 		ok = 0;
324*53a374c1SSascha Wildner 		for (i = 0; i < 5; i++) {
325*53a374c1SSascha Wildner 			ok = ssif_polled_request(sc, req);
326*53a374c1SSascha Wildner 			if (ok)
327*53a374c1SSascha Wildner 				break;
328*53a374c1SSascha Wildner 
329*53a374c1SSascha Wildner 			/* Wait 60 ms between retries. */
330*53a374c1SSascha Wildner 			tsleep(ssif_loop, 0, "retry", 60 * hz / 1000);
331*53a374c1SSascha Wildner #ifdef SSIF_RETRY_DEBUG
332*53a374c1SSascha Wildner 			device_printf(sc->ipmi_dev,
333*53a374c1SSascha Wildner 			    "SSIF: Retrying request (%d)\n", i + 1);
334*53a374c1SSascha Wildner #endif
335*53a374c1SSascha Wildner 		}
336*53a374c1SSascha Wildner 		if (ok)
337*53a374c1SSascha Wildner 			req->ir_error = 0;
338*53a374c1SSascha Wildner 		else
339*53a374c1SSascha Wildner 			req->ir_error = EIO;
340*53a374c1SSascha Wildner 		IPMI_LOCK(sc);
341*53a374c1SSascha Wildner 		ipmi_complete_request(sc, req);
342*53a374c1SSascha Wildner 		IPMI_UNLOCK(sc);
343*53a374c1SSascha Wildner 
344*53a374c1SSascha Wildner 		/* Enforce 10ms between requests. */
345*53a374c1SSascha Wildner 		tsleep(ssif_loop, 0, "delay", hz / 100);
346*53a374c1SSascha Wildner 
347*53a374c1SSascha Wildner 		IPMI_LOCK(sc);
348*53a374c1SSascha Wildner 	}
349*53a374c1SSascha Wildner 	IPMI_UNLOCK(sc);
350*53a374c1SSascha Wildner 	kthread_exit();
351*53a374c1SSascha Wildner }
352*53a374c1SSascha Wildner 
353*53a374c1SSascha Wildner static int
ssif_startup(struct ipmi_softc * sc)354*53a374c1SSascha Wildner ssif_startup(struct ipmi_softc *sc)
355*53a374c1SSascha Wildner {
356*53a374c1SSascha Wildner 
357*53a374c1SSascha Wildner 	return (kthread_create(ssif_loop, sc, &sc->ipmi_kthread,
358*53a374c1SSascha Wildner 	    "%s: ssif", device_get_nameunit(sc->ipmi_dev)));
359*53a374c1SSascha Wildner }
360*53a374c1SSascha Wildner 
361*53a374c1SSascha Wildner int
ipmi_ssif_attach(struct ipmi_softc * sc,device_t smbus,int smbus_address)362*53a374c1SSascha Wildner ipmi_ssif_attach(struct ipmi_softc *sc, device_t smbus, int smbus_address)
363*53a374c1SSascha Wildner {
364*53a374c1SSascha Wildner 
365*53a374c1SSascha Wildner 	/* Setup smbus address. */
366*53a374c1SSascha Wildner 	sc->ipmi_ssif_smbus = smbus;
367*53a374c1SSascha Wildner 	sc->ipmi_ssif_smbus_address = smbus_address;
368*53a374c1SSascha Wildner 
369*53a374c1SSascha Wildner 	/* Setup function pointers. */
370*53a374c1SSascha Wildner 	sc->ipmi_startup = ssif_startup;
371*53a374c1SSascha Wildner 	sc->ipmi_enqueue_request = ipmi_polled_enqueue_request;
372*53a374c1SSascha Wildner 
373*53a374c1SSascha Wildner 	return (0);
374*53a374c1SSascha Wildner }
375