1 /** $MirOS: src/sys/dev/ic/mpt_openbsd.c,v 1.2 2005/03/06 21:27:40 tg Exp $ */
2 /* $OpenBSD: mpt_openbsd.c,v 1.11 2004/04/28 01:45:48 marco Exp $ */
3 /* $NetBSD: mpt_netbsd.c,v 1.7 2003/07/14 15:47:11 lukem Exp $ */
4
5 /*
6 * Copyright (c) 2004 Milos Urbanek
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 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 */
25
26 /*
27 * Copyright (c) 2003 Wasabi Systems, Inc.
28 * All rights reserved.
29 *
30 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed for the NetBSD Project by
43 * Wasabi Systems, Inc.
44 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
45 * or promote products derived from this software without specific prior
46 * written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
59 */
60
61 /*
62 * Copyright (c) 2000, 2001 by Greg Ansley
63 * Partially derived from Matt Jacob's ISP driver.
64 *
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions
67 * are met:
68 * 1. Redistributions of source code must retain the above copyright
69 * notice immediately at the beginning of the file, without modification,
70 * this list of conditions, and the following disclaimer.
71 * 2. The name of the author may not be used to endorse or promote products
72 * derived from this software without specific prior written permission.
73 *
74 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
75 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
78 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
79 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
80 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
83 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
84 * SUCH DAMAGE.
85 */
86 /*
87 * Additional Copyright (c) 2002 by Matthew Jacob under same license.
88 */
89
90 /*
91 * mpt_openbsd.c:
92 *
93 * OpenBSD-specific routines for LSI Fusion adapters. Includes some
94 * bus_dma glue, and SCSI glue.
95 *
96 * Adapted from the NetBSD "mpt" driver by Milos Urbanek for
97 * ZOOM International, s.r.o.
98 */
99
100 #include <sys/cdefs.h>
101 /* __KERNEL_RCSID(0, "$NetBSD: mpt_netbsd.c,v 1.7 2003/07/14 15:47:11 lukem Exp $"); */
102
103 #include <dev/ic/mpt.h> /* pulls in all headers */
104
105 static void mpt_run_ppr(mpt_softc_t *);
106 static int mpt_ppr(mpt_softc_t *, struct scsi_link *, int speed);
107 static int mpt_poll(mpt_softc_t *, struct scsi_xfer *, int);
108 static void mpt_timeout(void *);
109 static void mpt_done(mpt_softc_t *, uint32_t);
110 static int mpt_run_xfer(mpt_softc_t *, struct scsi_xfer *);
111 static void mpt_check_xfer_settings(mpt_softc_t *, struct scsi_xfer *, MSG_SCSI_IO_REQUEST *);
112 static void mpt_ctlop(mpt_softc_t *, void *vmsg, uint32_t);
113 static void mpt_event_notify_reply(mpt_softc_t *, MSG_EVENT_NOTIFY_REPLY *);
114
115 static int mpt_action(struct scsi_xfer *);
116 static void mpt_minphys(struct buf *);
117
118 struct cfdriver mpt_cd = {
119 NULL, "mpt", DV_DULL
120 };
121
122 /* the below structure is so we have a default dev struct for our link struct */
123 static struct scsi_device mpt_dev =
124 {
125 NULL, /* Use default error handler */
126 NULL, /* have a queue, served by this */
127 NULL, /* have no async handler */
128 NULL, /* Use default 'done' routine */
129 };
130
131 enum mpt_scsi_speed { U320, U160, U80 };
132
133 /*
134 * try speed and
135 * return 0 if failed
136 * return 1 if passed
137 */
138 int
mpt_ppr(mpt_softc_t * mpt,struct scsi_link * sc_link,int speed)139 mpt_ppr(mpt_softc_t *mpt, struct scsi_link *sc_link, int speed)
140 {
141 fCONFIG_PAGE_SCSI_DEVICE_0 page0;
142 fCONFIG_PAGE_SCSI_DEVICE_1 page1;
143 struct scsi_inquiry scsi_cmd;
144 uint8_t tp;
145 int error;
146 struct scsi_inquiry_data inqbuf;
147
148 if (mpt->verbose > 1) {
149 mpt_prt(mpt, "Entering PPR");
150 }
151
152 if (mpt->is_fc) {
153 /*
154 * SCSI transport settings don't make any sense for
155 * Fibre Channel; silently ignore the request.
156 */
157 return 1; /* success */
158 }
159
160 /*
161 * Always allow disconnect; we don't have a way to disable
162 * it right now, in any case.
163 */
164 mpt->mpt_disc_enable |= (1 << sc_link->target);
165
166 /*
167 * Enable tagged queueing.
168 */
169 if (sc_link->quirks & SDEV_NOTAGS)
170 mpt->mpt_tag_enable &= ~(1 << sc_link->target);
171 else
172 mpt->mpt_tag_enable |= (1 << sc_link->target);
173
174 page1 = mpt->mpt_dev_page1[sc_link->target];
175
176 /*
177 * Set the wide/narrow parameter for the target.
178 */
179 if (sc_link->quirks & SDEV_NOWIDE)
180 page1.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE;
181 else {
182 page1.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE;
183 }
184
185 /*
186 * Set the synchronous parameters for the target.
187 */
188 page1.RequestedParameters &= ~(MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK |
189 MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK |
190 MPI_SCSIDEVPAGE1_RP_DT | MPI_SCSIDEVPAGE1_RP_QAS |
191 MPI_SCSIDEVPAGE1_RP_IU);
192 if (!(sc_link->quirks & SDEV_NOSYNC)) {
193 int factor, offset, np;
194
195 /*
196 * Factor:
197 * 0x08 = U320 = 6.25ns
198 * 0x09 = U160 = 12.5ns
199 * 0x0a = U80 = 25ns
200 */
201 factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff;
202 offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff;
203 np = 0;
204
205 switch (speed) {
206 case U320:
207 /* do nothing */
208 break;
209
210 case U160:
211 factor = 0x09; /* force U160 */
212 break;
213
214 case U80:
215 factor = 0x0a; /* force U80 */
216 }
217
218 if (factor < 0x9) {
219 /* Ultra320 enable QAS & IU */
220 np |= MPI_SCSIDEVPAGE1_RP_QAS | MPI_SCSIDEVPAGE1_RP_IU;
221 }
222 if (factor < 0xa) {
223 /* >= Ultra160 enable DT transfer */
224 np |= MPI_SCSIDEVPAGE1_RP_DT;
225 }
226 np |= (factor << 8) | (offset << 16);
227 page1.RequestedParameters |= np;
228 }
229
230 /* write parameters out to chip */
231 if (mpt_write_cfg_page(mpt, sc_link->target, &page1.Header)) {
232 mpt_prt(mpt, "unable to write Device Page 1");
233 return 0;
234 }
235
236 /* make sure the parameters were written */
237 if (mpt_read_cfg_page(mpt, sc_link->target, &page1.Header)) {
238 mpt_prt(mpt, "unable to read back Device Page 1");
239 return 0;
240 }
241
242 mpt->mpt_dev_page1[sc_link->target] = page1;
243 if (mpt->verbose > 1) {
244 mpt_prt(mpt,
245 "SPI Target %d Page 1: RequestedParameters %x Config %x",
246 sc_link->target,
247 mpt->mpt_dev_page1[sc_link->target].RequestedParameters,
248 mpt->mpt_dev_page1[sc_link->target].Configuration);
249 }
250
251 /*
252 * use INQUIRY for PPR two reasons:
253 * 1) actually transfer data at requested speed
254 * 2) no need to test for TUR QUIRK
255 */
256 bzero(&scsi_cmd, sizeof scsi_cmd);
257 scsi_cmd.opcode = INQUIRY;
258 bzero(&inqbuf, sizeof inqbuf);
259 /*
260 * Ask only for a minimal amount of data, since we only want to
261 * test data xfer not read all the INQUIRY data.
262 */
263 scsi_cmd.length = SID_INQUIRY_HDR + SID_SCSI2_ALEN;
264 error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)&scsi_cmd,
265 sizeof(scsi_cmd), (u_char *)&inqbuf, scsi_cmd.length, 0, 10000, NULL,
266 SCSI_DATA_IN);
267 if (error) {
268 mpt_prt(mpt, "Invalid INQUIRY on target: %d", sc_link->target);
269 return 0;
270 }
271
272 /* read page 0 back to figure out if the PPR worked */
273 page0 = mpt->mpt_dev_page0[sc_link->target];
274 if (mpt_read_cfg_page(mpt, sc_link->target, &page0.Header)) {
275 mpt_prt(mpt, "unable to read Device Page 0");
276 return 0;
277 }
278
279 if (mpt->verbose > 1) {
280 mpt_prt(mpt,
281 "SPI Tgt %d Page 0: NParms %x Information %x",
282 sc_link->target,
283 page0.NegotiatedParameters, page0.Information);
284 }
285
286 if (!(page0.NegotiatedParameters & 0x07) && (speed == U320)) {
287 /* if lowest 3 aren't set the PPR probably failed, retry with other parameters */
288 if (mpt->verbose > 1) {
289 mpt_prt(mpt, "U320 PPR failed");
290 }
291 return 0;
292 }
293
294 if ((((page0.NegotiatedParameters >> 8) & 0xff) > 0x09) && (speed == U160)) {
295 /* if transfer period > 0x09 then U160 PPR failed, retry */
296 if (mpt->verbose > 1) {
297 mpt_prt(mpt, "U160 PPR failed");
298 }
299 return 0;
300 }
301
302 /*
303 * Bit 3 - PPR rejected: The IOC sets this bit if the device rejects a PPR message.
304 * Bit 2 - WDTR Rejected: The IOC sets this bit if the device rejects a WDTR message.
305 * Bit 1 - SDTR Rejected: The IOC sets this bit if the device rejects a SDTR message.
306 * Bit 0 - 1 A SCSI SDTR, WDTR, or PPR negotiation has occurred with this device.
307 */
308 if (page0.Information & 0x0e) {
309 /* target rejected PPR message */
310 mpt_prt(mpt, "Target %d rejected PPR message with %02x",
311 sc_link->target,
312 (uint8_t)page0.Information);
313 return 0;
314 }
315
316 /* print PPR results */
317 switch ((page0.NegotiatedParameters >> 8) & 0xff) {
318 case 0x08:
319 tp = 160;
320 break;
321
322 case 0x09:
323 tp = 80;
324 break;
325
326 case 0x0a:
327 tp = 40;
328 break;
329
330 case 0x0b:
331 tp = 20;
332 break;
333
334 case 0x0c:
335 tp = 10;
336 break;
337
338 default:
339 tp = 0;
340 }
341
342 mpt_prt(mpt,
343 "target %d %s at %dMHz width %dbit offset %d QAS %d DT %d IU %d",
344 sc_link->target,
345 tp ? "Synchronous" : "Asynchronous",
346 tp,
347 (page0.NegotiatedParameters & 0x20000000) ? 16 : 8,
348 (page0.NegotiatedParameters >> 16) & 0xff,
349 (page0.NegotiatedParameters & 0x04) ? 1 : 0,
350 (page0.NegotiatedParameters & 0x02) ? 1 : 0,
351 (page0.NegotiatedParameters & 0x01) ? 1 : 0);
352
353 return 1; /* success */
354 }
355
356 /*
357 * Run PPR on all attached devices
358 */
359 void
mpt_run_ppr(mpt_softc_t * mpt)360 mpt_run_ppr(mpt_softc_t *mpt)
361 {
362 struct scsi_link *sc_link;
363 struct device *dev;
364 u_int8_t target;
365 u_int16_t buswidth;
366
367 /* walk device list */
368 for (dev = TAILQ_FIRST(&alldevs); dev != NULL;
369 dev = TAILQ_NEXT(dev, dv_list)) {
370 if (dev->dv_parent == (struct device *)mpt) {
371 /* found scsibus softc */
372 buswidth = ((struct scsi_link *)&mpt->sc_link)->adapter_buswidth;
373 /* printf("mpt_softc: %x scsibus: %x buswidth: %d\n",
374 mpt, dev, buswidth); */
375 /* walk target list */
376 for (target = 0; target < buswidth; target++) {
377 sc_link = ((struct scsibus_softc *)dev)->sc_link[target][0];
378 if ((sc_link != NULL)) {
379 /* got a device! run PPR */
380 /* FIXME: skip CPU devices since they can
381 * crash at U320 speeds */
382 /*if (device == cpu) {
383 continue;
384 }*/
385 if (mpt_ppr(mpt, sc_link, U320)) {
386 mpt->mpt_negotiated_speed[target] = U320;
387 continue;
388 }
389
390 if (mpt_ppr(mpt, sc_link, U160)) {
391 mpt->mpt_negotiated_speed[target] = U160;
392 continue;
393 }
394
395 if (mpt_ppr(mpt, sc_link, U80)) {
396 mpt->mpt_negotiated_speed[target] = U80;
397 continue;
398 }
399
400 } /* sc_link */
401 } /* for target */
402 } /* if dev */
403 } /* end for dev */
404 }
405
406 /*
407 * Complete attachment of hardware, include subdevices.
408 */
409 void
mpt_attach(mpt_softc_t * mpt)410 mpt_attach(mpt_softc_t *mpt)
411 {
412 struct scsi_link *lptr = &mpt->sc_link;
413
414 mpt->bus = 0; /* XXX ?? */
415
416 /* Fill in the scsi_adapter. */
417 mpt->sc_adapter.scsi_cmd = mpt_action;
418 mpt->sc_adapter.scsi_minphys = mpt_minphys;
419
420 /* Fill in the prototype scsi_link */
421 lptr->adapter_softc = mpt;
422 lptr->device = &mpt_dev;
423 lptr->adapter = &mpt->sc_adapter;
424 lptr->flags = 0;
425 lptr->luns = 8;
426
427 if (mpt->is_fc) {
428 lptr->adapter_buswidth = 256;
429 lptr->adapter_target = 256;
430 } else {
431 lptr->adapter_buswidth = 16;
432 lptr->adapter_target = mpt->mpt_ini_id;
433 }
434 lptr->openings = MPT_MAX_REQUESTS(mpt) / lptr->adapter_buswidth;
435
436 #ifdef MPT_DEBUG
437 mpt->verbose = 2;
438 #endif
439 (void) config_found(&mpt->mpt_dev, lptr, scsiprint);
440
441 /* done attaching now walk targets and PPR them */
442 /* FC does not do PPR */
443 if (!mpt->is_fc) {
444 mpt_run_ppr(mpt);
445 }
446 }
447
448 int
mpt_dma_mem_alloc(mpt_softc_t * mpt)449 mpt_dma_mem_alloc(mpt_softc_t *mpt)
450 {
451 bus_dma_segment_t reply_seg, request_seg;
452 int reply_rseg, request_rseg;
453 bus_addr_t pptr, end;
454 caddr_t vptr;
455 size_t len;
456 int error, i;
457
458 /* Check if we have already allocated the reply memory. */
459 if (mpt->reply != NULL)
460 return (0);
461
462 /*
463 * Allocate the request pool. This isn't really DMA'd memory,
464 * but it's a convenient place to do it.
465 */
466 len = sizeof(request_t) * MPT_MAX_REQUESTS(mpt);
467 mpt->request_pool = malloc(len, M_DEVBUF, M_WAITOK);
468 if (mpt->request_pool == NULL) {
469 printf("%s: unable to allocate request pool\n",
470 mpt->mpt_dev.dv_xname);
471 return (ENOMEM);
472 }
473 bzero(mpt->request_pool, len);
474 /*
475 * Allocate DMA resources for reply buffers.
476 */
477 error = bus_dmamem_alloc(mpt->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
478 &reply_seg, 1, &reply_rseg, 0);
479 if (error) {
480 printf("%s: unable to allocate reply area, error = %d\n",
481 mpt->mpt_dev.dv_xname, error);
482 goto fail_0;
483 }
484
485 error = bus_dmamem_map(mpt->sc_dmat, &reply_seg, reply_rseg, PAGE_SIZE,
486 (caddr_t *) &mpt->reply, BUS_DMA_COHERENT/*XXX*/);
487 if (error) {
488 printf("%s: unable to map reply area, error = %d\n",
489 mpt->mpt_dev.dv_xname, error);
490 goto fail_1;
491 }
492
493 error = bus_dmamap_create(mpt->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
494 0, 0, &mpt->reply_dmap);
495 if (error) {
496 printf("%s: unable to create reply DMA map, error = %d\n",
497 mpt->mpt_dev.dv_xname, error);
498 goto fail_2;
499 }
500
501 error = bus_dmamap_load(mpt->sc_dmat, mpt->reply_dmap, mpt->reply,
502 PAGE_SIZE, NULL, 0);
503 if (error) {
504 printf("%s: unable to load reply DMA map, error = %d\n",
505 mpt->mpt_dev.dv_xname, error);
506 goto fail_3;
507 }
508 mpt->reply_phys = mpt->reply_dmap->dm_segs[0].ds_addr;
509
510 /*
511 * Allocate DMA resources for request buffers.
512 */
513 error = bus_dmamem_alloc(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt),
514 PAGE_SIZE, 0, &request_seg, 1, &request_rseg, 0);
515 if (error) {
516 printf("%s: unable to allocate request area, error = %d\n",
517 mpt->mpt_dev.dv_xname, error);
518 goto fail_4;
519 }
520
521 error = bus_dmamem_map(mpt->sc_dmat, &request_seg, request_rseg,
522 MPT_REQ_MEM_SIZE(mpt), (caddr_t *) &mpt->request, 0);
523 if (error) {
524 printf("%s: unable to map request area, error = %d\n",
525 mpt->mpt_dev.dv_xname, error);
526 goto fail_5;
527 }
528
529 error = bus_dmamap_create(mpt->sc_dmat, MPT_REQ_MEM_SIZE(mpt), 1,
530 MPT_REQ_MEM_SIZE(mpt), 0, 0, &mpt->request_dmap);
531 if (error) {
532 printf("%s: unable to create request DMA map, error = %d\n",
533 mpt->mpt_dev.dv_xname, error);
534 goto fail_6;
535 }
536
537 error = bus_dmamap_load(mpt->sc_dmat, mpt->request_dmap, mpt->request,
538 MPT_REQ_MEM_SIZE(mpt), NULL, 0);
539 if (error) {
540 printf("%s: unable to load request DMA map, error = %d\n",
541 mpt->mpt_dev.dv_xname, error);
542 goto fail_7;
543 }
544 mpt->request_phys = mpt->request_dmap->dm_segs[0].ds_addr;
545
546 pptr = mpt->request_phys;
547 vptr = (caddr_t) mpt->request;
548 end = pptr + MPT_REQ_MEM_SIZE(mpt);
549
550 for (i = 0; pptr < end; i++) {
551 request_t *req = &mpt->request_pool[i];
552 req->index = i;
553
554 /* Store location of Request Data */
555 req->req_pbuf = pptr;
556 req->req_vbuf = vptr;
557
558 pptr += MPT_REQUEST_AREA;
559 vptr += MPT_REQUEST_AREA;
560
561 req->sense_pbuf = (pptr - MPT_SENSE_SIZE);
562 req->sense_vbuf = (vptr - MPT_SENSE_SIZE);
563
564 error = bus_dmamap_create(mpt->sc_dmat, MAXPHYS,
565 MPT_SGL_MAX, MAXPHYS, 0, 0, &req->dmap);
566 if (error) {
567 printf("%s: unable to create req %d DMA map, error = "
568 "%d", mpt->mpt_dev.dv_xname, i, error);
569 goto fail_8;
570 }
571 }
572
573 return (0);
574
575 fail_8:
576 for (--i; i >= 0; i--) {
577 request_t *req = &mpt->request_pool[i];
578 if (req->dmap != NULL)
579 bus_dmamap_destroy(mpt->sc_dmat, req->dmap);
580 }
581 bus_dmamap_unload(mpt->sc_dmat, mpt->request_dmap);
582 fail_7:
583 bus_dmamap_destroy(mpt->sc_dmat, mpt->request_dmap);
584 fail_6:
585 bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->request, PAGE_SIZE);
586 fail_5:
587 bus_dmamem_free(mpt->sc_dmat, &request_seg, request_rseg);
588 fail_4:
589 bus_dmamap_unload(mpt->sc_dmat, mpt->reply_dmap);
590 fail_3:
591 bus_dmamap_destroy(mpt->sc_dmat, mpt->reply_dmap);
592 fail_2:
593 bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->reply, PAGE_SIZE);
594 fail_1:
595 bus_dmamem_free(mpt->sc_dmat, &reply_seg, reply_rseg);
596 fail_0:
597 free(mpt->request_pool, M_DEVBUF);
598
599 mpt->reply = NULL;
600 mpt->request = NULL;
601 mpt->request_pool = NULL;
602
603 return (error);
604 }
605
606 int
mpt_intr(void * arg)607 mpt_intr(void *arg)
608 {
609 mpt_softc_t *mpt = arg;
610 int nrepl = 0;
611 uint32_t reply;
612
613 /*
614 if ((mpt_read(mpt, MPT_OFFSET_INTR_STATUS) & MPT_INTR_REPLY_READY) == 0)
615 return (0);
616 */
617
618 /*
619 * Speed up trick to save one PCI read.
620 * Reply FIFO replies 0xffffffff whenever
621 * MPT_OFFSET_INTR_STATUS & MPT_INTR_REPLY_READY == 0
622 *
623 */
624
625 reply = mpt_pop_reply_queue(mpt);
626
627 if (reply == 0xffffffff) {
628 /* check doorbell, this is error path not IO path */
629 /* FIXME for now ignore strays and doorbells */
630 return (0);
631 }
632
633 while (reply != MPT_REPLY_EMPTY) {
634 nrepl++;
635 if (mpt->verbose > 1) {
636 if ((reply & MPT_CONTEXT_REPLY) != 0) {
637 /* Address reply; IOC has something to say */
638 mpt_print_reply(MPT_REPLY_PTOV(mpt, reply));
639 } else {
640 /* Context reply; all went well */
641 mpt_prt(mpt, "context %u reply OK", reply);
642 }
643 }
644 mpt_done(mpt, reply);
645 reply = mpt_pop_reply_queue(mpt);
646 }
647 return (nrepl != 0);
648 }
649
650 void
mpt_prt(mpt_softc_t * mpt,const char * fmt,...)651 mpt_prt(mpt_softc_t *mpt, const char *fmt, ...)
652 {
653 va_list ap;
654
655 printf("%s: ", mpt->mpt_dev.dv_xname);
656 va_start(ap, fmt);
657 vprintf(fmt, ap);
658 va_end(ap);
659 printf("\n");
660 }
661
662 static int
mpt_poll(mpt_softc_t * mpt,struct scsi_xfer * xs,int count)663 mpt_poll(mpt_softc_t *mpt, struct scsi_xfer *xs, int count)
664 {
665
666 /* Timeouts are in msec, so we loop in 1000usec cycles */
667 while (count) {
668 mpt_intr(mpt);
669 if (xs->flags & ITSDONE) {
670 return (0);
671 }
672 delay(1000); /* only happens in boot, so ok */
673 count--;
674 }
675 return (1);
676 }
677
678 static void
mpt_timeout(void * arg)679 mpt_timeout(void *arg)
680 {
681 request_t *req = arg;
682 struct scsi_xfer *xs = req->xfer;
683 struct scsi_link *linkp = xs->sc_link;
684 mpt_softc_t *mpt = (void *) linkp->adapter_softc;
685 uint32_t oseq;
686 int s, index;
687
688 mpt_prt(mpt, "command timeout");
689 sc_print_addr(linkp);
690
691 s = splbio();
692
693 oseq = req->sequence;
694 mpt->timeouts++;
695 if (mpt_intr(mpt)) {
696 if (req->sequence != oseq) {
697 mpt_prt(mpt, "recovered from command timeout");
698 splx(s);
699 return;
700 }
701 }
702 mpt_prt(mpt,
703 "timeout on request index = 0x%x, seq = 0x%08x",
704 req->index, req->sequence);
705 mpt_check_doorbell(mpt);
706 mpt_prt(mpt, "Status 0x%08x, Mask 0x%08x, Doorbell 0x%08x",
707 mpt_read(mpt, MPT_OFFSET_INTR_STATUS),
708 mpt_read(mpt, MPT_OFFSET_INTR_MASK),
709 mpt_read(mpt, MPT_OFFSET_DOORBELL));
710 mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug));
711 if (mpt->verbose > 1)
712 mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf);
713
714 for(index = 0; index < MPT_MAX_REQUESTS(mpt); index++)
715 if (req == &mpt->request_pool[index]) {
716 req->debug = REQ_TIMEOUT;
717 break;
718 }
719
720 mpt_done(mpt, index);
721
722 splx(s);
723 }
724
725 static void
mpt_done(mpt_softc_t * mpt,uint32_t reply)726 mpt_done(mpt_softc_t *mpt, uint32_t reply)
727 {
728 struct scsi_xfer *xs = NULL;
729 struct scsi_link *linkp;
730 int index;
731 request_t *req;
732 MSG_REQUEST_HEADER *mpt_req;
733 MSG_SCSI_IO_REPLY *mpt_reply;
734
735
736 if ((reply & MPT_CONTEXT_REPLY) == 0) {
737 /* context reply (ok) */
738 mpt_reply = NULL;
739 index = reply & MPT_CONTEXT_MASK;
740 } else {
741 /* address reply (error) */
742
743 /* XXX BUS_DMASYNC_POSTREAD XXX */
744 mpt_reply = MPT_REPLY_PTOV(mpt, reply);
745 if (mpt->verbose > 1) {
746 uint32_t *pReply = (uint32_t *) mpt_reply;
747
748 mpt_prt(mpt, "Address Reply (index %u):",
749 mpt_reply->MsgContext & 0xffff);
750 mpt_prt(mpt, "%08x %08x %08x %08x",
751 pReply[0], pReply[1], pReply[2], pReply[3]);
752 mpt_prt(mpt, "%08x %08x %08x %08x",
753 pReply[4], pReply[5], pReply[6], pReply[7]);
754 mpt_prt(mpt, "%08x %08x %08x %08x",
755 pReply[8], pReply[9], pReply[10], pReply[11]);
756 }
757 index = mpt_reply->MsgContext;
758 }
759
760 /*
761 * Address reply with MessageContext high bit set.
762 * This is most likely a notify message, so we try
763 * to process it, then free it.
764 */
765 if ((index & 0x80000000) != 0) {
766 if (mpt_reply != NULL)
767 mpt_ctlop(mpt, mpt_reply, reply);
768 else
769 mpt_prt(mpt, "mpt_done: index 0x%x, NULL reply", index);
770 return;
771 }
772
773 /* Did we end up with a valid index into the table? */
774 if (index < 0 || index >= MPT_MAX_REQUESTS(mpt)) {
775 mpt_prt(mpt, "mpt_done: invalid index (0x%x) in reply", index);
776 return;
777 }
778
779 req = &mpt->request_pool[index];
780
781 /* Make sure memory hasn't been trashed. */
782 if (req->index != index) {
783 mpt_prt(mpt, "mpt_done: corrupted request_t (0x%x)", index);
784 return;
785 }
786
787 MPT_SYNC_REQ(mpt, req, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
788 mpt_req = req->req_vbuf;
789
790 /* Short cut for task management replies; nothing more for us to do. */
791 if (mpt_req->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
792 if (mpt->verbose > 1)
793 mpt_prt(mpt, "mpt_done: TASK MGMT");
794 goto done;
795 }
796
797 if (mpt_req->Function == MPI_FUNCTION_PORT_ENABLE)
798 goto done;
799
800 /*
801 * At this point, it had better be a SCSI I/O command, but don't
802 * crash if it isn't.
803 */
804 if (mpt_req->Function != MPI_FUNCTION_SCSI_IO_REQUEST) {
805 if (mpt->verbose > 1)
806 mpt_prt(mpt, "mpt_done: unknown Function 0x%x (0x%x)",
807 mpt_req->Function, index);
808 goto done;
809 }
810
811 /* Recover scsi_xfer from the request structure. */
812 xs = req->xfer;
813
814 /* Can't have a SCSI command without a scsi_xfer. */
815 if (xs == NULL) {
816 mpt_prt(mpt,
817 "mpt_done: no scsi_xfer, index = 0x%x, seq = 0x%08x",
818 req->index, req->sequence);
819 mpt_prt(mpt, "request state: %s", mpt_req_state(req->debug));
820 mpt_prt(mpt, "mpt_request:");
821 mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf);
822
823 if (mpt_reply != NULL) {
824 mpt_prt(mpt, "mpt_reply:");
825 mpt_print_reply(mpt_reply);
826 } else {
827 mpt_prt(mpt, "context reply: 0x%08x", reply);
828 }
829 goto done;
830 }
831
832 timeout_del(&xs->stimeout);
833
834 linkp = xs->sc_link;
835
836 /*
837 * If we were a data transfer, unload the map that described
838 * the data buffer.
839 */
840 if (xs->datalen != 0) {
841 bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0,
842 req->dmap->dm_mapsize,
843 (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD
844 : BUS_DMASYNC_POSTWRITE);
845 bus_dmamap_unload(mpt->sc_dmat, req->dmap);
846 }
847
848 if (req->debug == REQ_TIMEOUT) {
849 xs->error = XS_TIMEOUT;
850 xs->status = SCSI_OK;
851 xs->resid = 0;
852 goto done;
853 } else if (mpt_reply == NULL) {
854 /*
855 * Context reply; report that the command was
856 * successful!
857 *
858 * Also report the xfer mode, if necessary.
859 */
860 #if 0 /*XXX report xfer mode not impl */
861 if (mpt->mpt_report_xfer_mode != 0) {
862 if ((mpt->mpt_report_xfer_mode &
863 (1 << periph->periph_target)) != 0)
864 mpt_get_xfer_mode(mpt, periph);
865 }
866 #endif
867 xs->error = XS_NOERROR;
868 xs->status = SCSI_OK;
869 xs->resid = 0;
870 goto done;
871 }
872
873 xs->status = mpt_reply->SCSIStatus;
874 switch (mpt_reply->IOCStatus) {
875 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
876 xs->error = XS_DRIVER_STUFFUP;
877 break;
878
879 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
880 /*
881 * Yikes! Tagged queue full comes through this path!
882 *
883 * So we'll change it to a status error and anything
884 * that returns status should probably be a status
885 * error as well.
886 */
887 xs->resid = xs->datalen - mpt_reply->TransferCount;
888 if (mpt_reply->SCSIState &
889 MPI_SCSI_STATE_NO_SCSI_STATUS) {
890 xs->error = XS_DRIVER_STUFFUP;
891 break;
892 }
893 /* FALLTHROUGH */
894 case MPI_IOCSTATUS_SUCCESS:
895 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:
896 switch (xs->status) {
897 case SCSI_OK:
898 #if 0 /* XXX xfer mode */
899 /* Report the xfer mode, if necessary. */
900 if ((mpt->mpt_report_xfer_mode &
901 (1 << periph->periph_target)) != 0)
902 mpt_get_xfer_mode(mpt, periph);
903 #endif
904 xs->resid = 0;
905 break;
906
907 case SCSI_CHECK:
908 xs->error = XS_SENSE;
909 break;
910
911 case SCSI_BUSY:
912 xs->error = XS_BUSY;
913 break;
914
915 case SCSI_QUEUE_FULL:
916 xs->error = XS_TIMEOUT;
917 xs->retries++;
918 break;
919 default:
920 sc_print_addr(linkp);
921 mpt_prt(mpt, "invalid status code %d", xs->status);
922 xs->error = XS_DRIVER_STUFFUP;
923 break;
924 }
925 break;
926
927 #if 0 /* XS_RESOURCE_SHORTAGE not impl */
928 case MPI_IOCSTATUS_BUSY:
929 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
930 xs->error = XS_RESOURCE_SHORTAGE;
931 break;
932 #endif
933 case MPI_IOCSTATUS_SCSI_INVALID_BUS:
934 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
935 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
936 xs->error = XS_SELTIMEOUT;
937 break;
938
939 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
940 xs->error = XS_DRIVER_STUFFUP;
941 break;
942
943 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
944 xs->error = XS_DRIVER_STUFFUP;
945 break;
946
947 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
948 /* XXX */
949 xs->error = XS_DRIVER_STUFFUP;
950 break;
951
952 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
953 /* XXX */
954 xs->error = XS_DRIVER_STUFFUP;
955 break;
956
957 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
958 /* XXX This is a bus-reset */
959 xs->error = XS_DRIVER_STUFFUP;
960 break;
961
962 default:
963 /* XXX unrecognized HBA error */
964 xs->error = XS_DRIVER_STUFFUP;
965 break;
966 }
967
968 if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
969 memcpy(&xs->sense, req->sense_vbuf,
970 sizeof(xs->sense));
971 } else if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
972 /*
973 * This will cause the scsi layer to issue
974 * a REQUEST SENSE.
975 */
976 if (xs->status == SCSI_CHECK)
977 xs->error = XS_BUSY;
978 }
979
980 done:
981 /* If IOC done with this requeset, free it up. */
982 if (mpt_reply == NULL || (mpt_reply->MsgFlags & 0x80) == 0)
983 mpt_free_request(mpt, req);
984
985 /* If address reply, give the buffer back to the IOC. */
986 if (mpt_reply != NULL)
987 mpt_free_reply(mpt, (reply << 1));
988
989 if (xs != NULL) {
990 xs->flags |= ITSDONE;
991 scsi_done(xs);
992 }
993 }
994
995 static int
mpt_run_xfer(mpt_softc_t * mpt,struct scsi_xfer * xs)996 mpt_run_xfer(mpt_softc_t *mpt, struct scsi_xfer *xs)
997 {
998 struct scsi_link *linkp = xs->sc_link;
999 request_t *req;
1000 MSG_SCSI_IO_REQUEST *mpt_req;
1001 int error, s;
1002
1003 s = splbio();
1004 req = mpt_get_request(mpt);
1005 if (req == NULL) {
1006 /* This should happen very infrequently. */
1007 xs->error = XS_DRIVER_STUFFUP;
1008 /*
1009 xs->error = XS_RESOURCE_SHORTAGE;
1010 */
1011 xs->flags |= ITSDONE;
1012 scsi_done(xs);
1013 splx(s);
1014 return (COMPLETE);
1015 }
1016 splx(s);
1017
1018 /* Link the req and the scsi_xfer. */
1019 req->xfer = xs;
1020
1021 /* Now we build the command for the IOC */
1022 mpt_req = req->req_vbuf;
1023 bzero(mpt_req, sizeof(*mpt_req));
1024
1025 mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
1026 mpt_req->Bus = mpt->bus;
1027
1028 mpt_req->SenseBufferLength =
1029 (sizeof(xs->sense) < MPT_SENSE_SIZE) ?
1030 sizeof(xs->sense) : MPT_SENSE_SIZE;
1031
1032 /*
1033 * We use the message context to find the request structure when
1034 * we get the command completion interrupt from the IOC.
1035 */
1036 mpt_req->MsgContext = req->index;
1037
1038 /* Which physical device to do the I/O on. */
1039 mpt_req->TargetID = linkp->target;
1040 mpt_req->LUN[1] = linkp->lun;
1041
1042 /* Set the direction of the transfer. */
1043 if (xs->flags & SCSI_DATA_IN)
1044 mpt_req->Control = MPI_SCSIIO_CONTROL_READ;
1045 else if (xs->flags & SCSI_DATA_OUT)
1046 mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE;
1047 else
1048 mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER;
1049
1050 mpt_check_xfer_settings(mpt, xs, mpt_req);
1051
1052 /* Copy the SCSI command block into place. */
1053 memcpy(mpt_req->CDB, xs->cmd, xs->cmdlen);
1054
1055 mpt_req->CDBLength = xs->cmdlen;
1056 mpt_req->DataLength = xs->datalen;
1057 mpt_req->SenseBufferLowAddr = req->sense_pbuf;
1058
1059 /*
1060 * Map the DMA transfer.
1061 */
1062 if (xs->datalen) {
1063 SGE_SIMPLE32 *se;
1064
1065 error = bus_dmamap_load(mpt->sc_dmat, req->dmap, xs->data,
1066 xs->datalen, NULL,
1067 ((xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT
1068 : BUS_DMA_WAITOK) |
1069 BUS_DMA_STREAMING |
1070 ((xs->flags & SCSI_DATA_IN) ? BUS_DMA_READ
1071 : BUS_DMA_WRITE));
1072 switch (error) {
1073 case 0:
1074 break;
1075
1076 case ENOMEM:
1077 case EAGAIN:
1078 xs->error = XS_DRIVER_STUFFUP;
1079 /* xs->error = XS_RESOURCE_SHORTAGE; */
1080 goto out_bad;
1081 default:
1082 xs->error = XS_DRIVER_STUFFUP;
1083 mpt_prt(mpt, "error %d loading DMA map", error);
1084 out_bad:
1085 s = splbio();
1086 mpt_free_request(mpt, req);
1087 xs->flags |= ITSDONE;
1088 scsi_done(xs);
1089 splx(s);
1090 return (TRY_AGAIN_LATER);
1091 }
1092
1093 if (req->dmap->dm_nsegs > MPT_NSGL_FIRST(mpt)) {
1094 int seg, i, nleft = req->dmap->dm_nsegs;
1095 uint32_t flags;
1096 SGE_CHAIN32 *ce;
1097
1098 seg = 0;
1099
1100 mpt_req->DataLength = xs->datalen;
1101 flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
1102 if (xs->flags & SCSI_DATA_OUT)
1103 flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
1104
1105 se = (SGE_SIMPLE32 *) &mpt_req->SGL;
1106 for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1;
1107 i++, se++, seg++) {
1108 uint32_t tf;
1109
1110 bzero(se, sizeof(*se));
1111 se->Address = req->dmap->dm_segs[seg].ds_addr;
1112 MPI_pSGE_SET_LENGTH(se,
1113 req->dmap->dm_segs[seg].ds_len);
1114 tf = flags;
1115 if (i == MPT_NSGL_FIRST(mpt) - 2)
1116 tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
1117 MPI_pSGE_SET_FLAGS(se, tf);
1118 nleft--;
1119 }
1120
1121 /*
1122 * Tell the IOC where to find the first chain element.
1123 */
1124 mpt_req->ChainOffset =
1125 ((char *)se - (char *)mpt_req) >> 2;
1126
1127 /*
1128 * Until we're finished with all segments...
1129 */
1130 while (nleft) {
1131 int ntodo;
1132
1133 /*
1134 * Construct the chain element that points to
1135 * the next segment.
1136 */
1137 ce = (SGE_CHAIN32 *) se++;
1138 if (nleft > MPT_NSGL(mpt)) {
1139 ntodo = MPT_NSGL(mpt) - 1;
1140 ce->NextChainOffset = (MPT_RQSL(mpt) -
1141 sizeof(SGE_SIMPLE32)) >> 2;
1142 ce->Length = MPT_NSGL(mpt)
1143 * sizeof(SGE_SIMPLE32);
1144 } else {
1145 ntodo = nleft;
1146 ce->NextChainOffset = 0;
1147 ce->Length = ntodo
1148 * sizeof(SGE_SIMPLE32);
1149 }
1150 ce->Address = req->req_pbuf +
1151 ((char *)se - (char *)mpt_req);
1152 ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1153 for (i = 0; i < ntodo; i++, se++, seg++) {
1154 uint32_t tf;
1155
1156 bzero(se, sizeof(*se));
1157 se->Address =
1158 req->dmap->dm_segs[seg].ds_addr;
1159 MPI_pSGE_SET_LENGTH(se,
1160 req->dmap->dm_segs[seg].ds_len);
1161 tf = flags;
1162 if (i == ntodo - 1) {
1163 tf |=
1164 MPI_SGE_FLAGS_LAST_ELEMENT;
1165 if (ce->NextChainOffset == 0) {
1166 tf |=
1167 MPI_SGE_FLAGS_END_OF_LIST |
1168 MPI_SGE_FLAGS_END_OF_BUFFER;
1169 }
1170 }
1171 MPI_pSGE_SET_FLAGS(se, tf);
1172 nleft--;
1173 }
1174 }
1175 bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0,
1176 req->dmap->dm_mapsize,
1177 (xs->flags & SCSI_DATA_IN) ?
1178 BUS_DMASYNC_PREREAD
1179 : BUS_DMASYNC_PREWRITE);
1180 } else {
1181 int i;
1182 uint32_t flags;
1183
1184 mpt_req->DataLength = xs->datalen;
1185 flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
1186 if (xs->flags & SCSI_DATA_OUT)
1187 flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
1188
1189 /* Copy the segments into our SG list. */
1190 se = (SGE_SIMPLE32 *) &mpt_req->SGL;
1191 for (i = 0; i < req->dmap->dm_nsegs;
1192 i++, se++) {
1193 uint32_t tf;
1194
1195 bzero(se, sizeof(*se));
1196 se->Address = req->dmap->dm_segs[i].ds_addr;
1197 MPI_pSGE_SET_LENGTH(se,
1198 req->dmap->dm_segs[i].ds_len);
1199 tf = flags;
1200 if (i == req->dmap->dm_nsegs - 1) {
1201 tf |=
1202 MPI_SGE_FLAGS_LAST_ELEMENT |
1203 MPI_SGE_FLAGS_END_OF_BUFFER |
1204 MPI_SGE_FLAGS_END_OF_LIST;
1205 }
1206 MPI_pSGE_SET_FLAGS(se, tf);
1207 }
1208 bus_dmamap_sync(mpt->sc_dmat, req->dmap, 0,
1209 req->dmap->dm_mapsize,
1210 (xs->flags & SCSI_DATA_IN) ?
1211 BUS_DMASYNC_PREREAD
1212 : BUS_DMASYNC_PREWRITE);
1213 }
1214 } else {
1215 /*
1216 * No data to transfer; just make a single simple SGL
1217 * with zero length.
1218 */
1219 SGE_SIMPLE32 *se = (SGE_SIMPLE32 *) &mpt_req->SGL;
1220 bzero(se, sizeof(*se));
1221 MPI_pSGE_SET_FLAGS(se,
1222 (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
1223 MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
1224 }
1225
1226 if (mpt->verbose > 1)
1227 mpt_print_scsi_io_request(mpt_req);
1228
1229 s = splbio();
1230
1231 /* Always reset xs->stimeout, lest we timeout_del() with trash */
1232 timeout_set(&xs->stimeout, mpt_timeout, req);
1233
1234 if ((xs->flags & SCSI_POLL) == 0)
1235 timeout_add(&xs->stimeout, mstohz(xs->timeout));
1236 mpt_send_cmd(mpt, req);
1237 splx(s);
1238
1239 if ((xs->flags & SCSI_POLL) == 0) {
1240 return (SUCCESSFULLY_QUEUED);
1241 }
1242 /*
1243 * If we can't use interrupts, poll on completion.
1244 */
1245 if (mpt_poll(mpt, xs, xs->timeout)) {
1246 mpt_timeout(req);
1247 /* XXX scsi_done called
1248 return (TRY_AGAIN_LATER);
1249 */
1250 return (COMPLETE);
1251 }
1252
1253 return (COMPLETE);
1254 }
1255
1256 static void
mpt_ctlop(mpt_softc_t * mpt,void * vmsg,uint32_t reply)1257 mpt_ctlop(mpt_softc_t *mpt, void *vmsg, uint32_t reply)
1258 {
1259 MSG_DEFAULT_REPLY *dmsg = vmsg;
1260
1261 switch (dmsg->Function) {
1262 case MPI_FUNCTION_EVENT_NOTIFICATION:
1263 mpt_event_notify_reply(mpt, vmsg);
1264 mpt_free_reply(mpt, (reply << 1));
1265 break;
1266
1267 case MPI_FUNCTION_EVENT_ACK:
1268 mpt_free_reply(mpt, (reply << 1));
1269 break;
1270
1271 case MPI_FUNCTION_PORT_ENABLE:
1272 {
1273 MSG_PORT_ENABLE_REPLY *msg = vmsg;
1274 int index = msg->MsgContext & ~0x80000000;
1275 if (mpt->verbose > 1)
1276 mpt_prt(mpt, "enable port reply index %d", index);
1277 if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) {
1278 request_t *req = &mpt->request_pool[index];
1279 req->debug = REQ_DONE;
1280 }
1281 mpt_free_reply(mpt, (reply << 1));
1282 break;
1283 }
1284
1285 case MPI_FUNCTION_CONFIG:
1286 {
1287 MSG_CONFIG_REPLY *msg = vmsg;
1288 int index = msg->MsgContext & ~0x80000000;
1289 if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) {
1290 request_t *req = &mpt->request_pool[index];
1291 req->debug = REQ_DONE;
1292 req->sequence = reply;
1293 } else
1294 mpt_free_reply(mpt, (reply << 1));
1295 break;
1296 }
1297
1298 default:
1299 mpt_prt(mpt, "unknown ctlop: 0x%x", dmsg->Function);
1300 }
1301 }
1302
1303 static void
mpt_event_notify_reply(mpt_softc_t * mpt,MSG_EVENT_NOTIFY_REPLY * msg)1304 mpt_event_notify_reply(mpt_softc_t *mpt, MSG_EVENT_NOTIFY_REPLY *msg)
1305 {
1306
1307 switch (msg->Event) {
1308 case MPI_EVENT_LOG_DATA:
1309 {
1310 int i;
1311
1312 /* Some error occurrerd that the Fusion wants logged. */
1313 mpt_prt(mpt, "EvtLogData: IOCLogInfo: 0x%08x", msg->IOCLogInfo);
1314 mpt_prt(mpt, "EvtLogData: Event Data:");
1315 for (i = 0; i < msg->EventDataLength; i++) {
1316 if ((i % 4) == 0)
1317 printf("%s:\t", mpt->mpt_dev.dv_xname);
1318 printf("0x%08x%c", msg->Data[i],
1319 ((i % 4) == 3) ? '\n' : ' ');
1320 }
1321 if ((i % 4) != 0)
1322 printf("\n");
1323 break;
1324 }
1325
1326 case MPI_EVENT_UNIT_ATTENTION:
1327 mpt_prt(mpt, "Unit Attn: Bus 0x%02x Target 0x%02x",
1328 (msg->Data[0] >> 8) & 0xff, msg->Data[0] & 0xff);
1329 break;
1330
1331 case MPI_EVENT_IOC_BUS_RESET:
1332 /* We generated a bus reset. */
1333 mpt_prt(mpt, "IOC Bus Reset Port %d",
1334 (msg->Data[0] >> 8) & 0xff);
1335 break;
1336
1337 case MPI_EVENT_EXT_BUS_RESET:
1338 /* Someone else generated a bus reset. */
1339 mpt_prt(mpt, "External Bus Reset");
1340 /*
1341 * These replies don't return EventData like the MPI
1342 * spec says they do.
1343 */
1344 /* XXX Send an async event? */
1345 break;
1346
1347 case MPI_EVENT_RESCAN:
1348 /*
1349 * In general, thise means a device has been added
1350 * to the loop.
1351 */
1352 mpt_prt(mpt, "Rescan Port %d", (msg->Data[0] >> 8) & 0xff);
1353 /* XXX Send an async event? */
1354 break;
1355
1356 case MPI_EVENT_LINK_STATUS_CHANGE:
1357 mpt_prt(mpt, "Port %d: Link state %s",
1358 (msg->Data[1] >> 8) & 0xff,
1359 (msg->Data[0] & 0xff) == 0 ? "Failed" : "Active");
1360 break;
1361
1362 case MPI_EVENT_LOOP_STATE_CHANGE:
1363 switch ((msg->Data[0] >> 16) & 0xff) {
1364 case 0x01:
1365 mpt_prt(mpt,
1366 "Port %d: FC Link Event: LIP(%02x,%02x) "
1367 "(Loop Initialization)",
1368 (msg->Data[1] >> 8) & 0xff,
1369 (msg->Data[0] >> 8) & 0xff,
1370 (msg->Data[0] ) & 0xff);
1371 switch ((msg->Data[0] >> 8) & 0xff) {
1372 case 0xf7:
1373 if ((msg->Data[0] & 0xff) == 0xf7)
1374 mpt_prt(mpt, "\tDevice needs AL_PA");
1375 else
1376 mpt_prt(mpt, "\tDevice %02x doesn't "
1377 "like FC performance",
1378 msg->Data[0] & 0xff);
1379 break;
1380
1381 case 0xf8:
1382 if ((msg->Data[0] & 0xff) == 0xf7)
1383 mpt_prt(mpt, "\tDevice detected loop "
1384 "failure before acquiring AL_PA");
1385 else
1386 mpt_prt(mpt, "\tDevice %02x detected "
1387 "loop failure",
1388 msg->Data[0] & 0xff);
1389 break;
1390
1391 default:
1392 mpt_prt(mpt, "\tDevice %02x requests that "
1393 "device %02x reset itself",
1394 msg->Data[0] & 0xff,
1395 (msg->Data[0] >> 8) & 0xff);
1396 break;
1397 }
1398 break;
1399
1400 case 0x02:
1401 mpt_prt(mpt, "Port %d: FC Link Event: LPE(%02x,%02x) "
1402 "(Loop Port Enable)",
1403 (msg->Data[1] >> 8) & 0xff,
1404 (msg->Data[0] >> 8) & 0xff,
1405 (msg->Data[0] ) & 0xff);
1406 break;
1407
1408 case 0x03:
1409 mpt_prt(mpt, "Port %d: FC Link Event: LPB(%02x,%02x) "
1410 "(Loop Port Bypass)",
1411 (msg->Data[1] >> 8) & 0xff,
1412 (msg->Data[0] >> 8) & 0xff,
1413 (msg->Data[0] ) & 0xff);
1414 break;
1415
1416 default:
1417 mpt_prt(mpt, "Port %d: FC Link Event: "
1418 "Unknown event (%02x %02x %02x)",
1419 (msg->Data[1] >> 8) & 0xff,
1420 (msg->Data[0] >> 16) & 0xff,
1421 (msg->Data[0] >> 8) & 0xff,
1422 (msg->Data[0] ) & 0xff);
1423 break;
1424 }
1425 break;
1426
1427 case MPI_EVENT_LOGOUT:
1428 mpt_prt(mpt, "Port %d: FC Logout: N_PortID: %02x",
1429 (msg->Data[1] >> 8) & 0xff, msg->Data[0]);
1430 break;
1431
1432 case MPI_EVENT_EVENT_CHANGE:
1433 /*
1434 * This is just an acknowledgement of our
1435 * mpt_send_event_request().
1436 */
1437 break;
1438
1439 default:
1440 mpt_prt(mpt, "Unknown async event: 0x%x", msg->Event);
1441 break;
1442 }
1443
1444 if (msg->AckRequired) {
1445 MSG_EVENT_ACK *ackp;
1446 request_t *req;
1447
1448 if ((req = mpt_get_request(mpt)) == NULL) {
1449 /* XXX XXX XXX XXXJRT */
1450 panic("mpt_event_notify_reply: unable to allocate "
1451 "request structure");
1452 }
1453
1454 ackp = (MSG_EVENT_ACK *) req->req_vbuf;
1455 bzero(ackp, sizeof(*ackp));
1456 ackp->Function = MPI_FUNCTION_EVENT_ACK;
1457 ackp->Event = msg->Event;
1458 ackp->EventContext = msg->EventContext;
1459 ackp->MsgContext = req->index | 0x80000000;
1460 mpt_check_doorbell(mpt);
1461 mpt_send_cmd(mpt, req);
1462 }
1463 }
1464
1465 void
mpt_check_xfer_settings(mpt_softc_t * mpt,struct scsi_xfer * xs,MSG_SCSI_IO_REQUEST * mpt_req)1466 mpt_check_xfer_settings(mpt_softc_t *mpt, struct scsi_xfer *xs, MSG_SCSI_IO_REQUEST *mpt_req)
1467 {
1468 if (mpt->is_fc) {
1469 /*
1470 * SCSI transport settings don't make any sense for
1471 * Fibre Channel; silently ignore the request.
1472 */
1473 return;
1474 }
1475
1476 /*
1477 * XXX never do these commands with tags. Should really be
1478 * in a higher layer.
1479 */
1480 if (xs->cmd->opcode == INQUIRY ||
1481 xs->cmd->opcode == TEST_UNIT_READY ||
1482 xs->cmd->opcode == REQUEST_SENSE)
1483 return;
1484
1485 /* Set the queue behavior. */
1486 if (mpt->is_fc || (mpt->mpt_tag_enable & (1 << xs->sc_link->target))) {
1487 mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ;
1488 } else {
1489 mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED;
1490 mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT;
1491 }
1492 #if 0
1493 if (mpt->is_fc == 0 && (mpt->mpt_disc_enable &
1494 (1 << linkp->target)) == 0)
1495 mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT;
1496 #endif
1497 return;
1498 }
1499
1500 /* XXXJRT mpt_bus_reset() */
1501
1502 /*****************************************************************************
1503 * SCSI interface routines
1504 *****************************************************************************/
1505
1506 static int
mpt_action(struct scsi_xfer * xfer)1507 mpt_action(struct scsi_xfer *xfer)
1508 {
1509 mpt_softc_t *mpt = (void *) xfer->sc_link->adapter_softc;
1510 int ret;
1511
1512 ret = mpt_run_xfer(mpt, xfer);
1513 return ret;
1514 #if 0
1515 switch (req) {
1516 case ADAPTER_REQ_RUN_XFER:
1517 mpt_run_xfer(mpt, (struct scsipi_xfer *) arg);
1518 return;
1519
1520 case ADAPTER_REQ_GROW_RESOURCES:
1521 /* Not supported. */
1522 return;
1523
1524 case ADAPTER_REQ_SET_XFER_MODE:
1525 mpt_set_xfer_mode(mpt, (struct scsipi_xfer_mode *) arg);
1526 return;
1527 }
1528 #endif
1529 }
1530
1531 static void
mpt_minphys(struct buf * bp)1532 mpt_minphys(struct buf *bp)
1533 {
1534
1535 /*
1536 * Subtract one from the SGL limit, since we need an extra one to handle
1537 * an non-page-aligned transfer.
1538 */
1539 #define MPT_MAX_XFER ((MPT_SGL_MAX - 1) * PAGE_SIZE)
1540
1541 if (bp->b_bcount > MPT_MAX_XFER)
1542 bp->b_bcount = MPT_MAX_XFER;
1543 minphys(bp);
1544 }
1545
1546 /*
1547 * Allocate DMA resources for FW image
1548 *
1549 * img_sz : size of image
1550 * maxsgl : maximum number of DMA segments
1551 */
1552 int
mpt_alloc_fw_mem(mpt_softc_t * mpt,uint32_t img_sz,int maxsgl)1553 mpt_alloc_fw_mem(mpt_softc_t *mpt, uint32_t img_sz, int maxsgl)
1554 {
1555 int error;
1556
1557 error = bus_dmamem_alloc(mpt->sc_dmat, img_sz, PAGE_SIZE, 0,
1558 &mpt->fw_seg, maxsgl, &mpt->fw_rseg, 0);
1559 if (error) {
1560 mpt_prt(mpt, "unable to allocate fw memory, error = %d", error);
1561 goto fw_fail0;
1562 }
1563
1564 error = bus_dmamem_map(mpt->sc_dmat, &mpt->fw_seg, mpt->fw_rseg, img_sz,
1565 (caddr_t *)&mpt->fw, BUS_DMA_COHERENT);
1566 if (error) {
1567 mpt_prt(mpt, "unable to map fw area, error = %d", error);
1568 goto fw_fail1;
1569 }
1570
1571 error = bus_dmamap_create(mpt->sc_dmat, img_sz, maxsgl, img_sz,
1572 0, 0, &mpt->fw_dmap);
1573 if (error) {
1574 mpt_prt(mpt, "unable to create request DMA map, error = %d",
1575 error);
1576 goto fw_fail2;
1577 }
1578
1579 error = bus_dmamap_load(mpt->sc_dmat, mpt->fw_dmap, mpt->fw, img_sz,
1580 NULL, 0);
1581 if (error) {
1582 mpt_prt(mpt, "unable to load request DMA map, error = %d", error);
1583 goto fw_fail3;
1584 }
1585
1586 return(error);
1587 fw_fail3:
1588 bus_dmamap_unload(mpt->sc_dmat, mpt->fw_dmap);
1589 fw_fail2:
1590 bus_dmamap_destroy(mpt->sc_dmat, mpt->fw_dmap);
1591 fw_fail1:
1592 bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->fw, img_sz);
1593 fw_fail0:
1594 bus_dmamem_free(mpt->sc_dmat, &mpt->fw_seg, mpt->fw_rseg);
1595
1596 mpt->fw = NULL;
1597 return (error);
1598 }
1599
1600 void
mpt_free_fw_mem(mpt_softc_t * mpt)1601 mpt_free_fw_mem(mpt_softc_t *mpt)
1602 {
1603 bus_dmamap_unload(mpt->sc_dmat, mpt->fw_dmap);
1604 bus_dmamap_destroy(mpt->sc_dmat, mpt->fw_dmap);
1605 bus_dmamem_unmap(mpt->sc_dmat, (caddr_t)mpt->fw, mpt->fw_image_size);
1606 bus_dmamem_free(mpt->sc_dmat, &mpt->fw_seg, mpt->fw_rseg);
1607 }
1608