Merge from vendor branch LIBSTDC++:
[dragonfly.git] / sys / dev / disk / mpt / mpt_freebsd.c
1 /* $FreeBSD: src/sys/dev/mpt/mpt_freebsd.c,v 1.3.2.3 2002/09/24 21:37:25 mjacob Exp $ */
2 /* $DragonFly: src/sys/dev/disk/mpt/mpt_freebsd.c,v 1.3 2003/08/07 21:16:53 dillon Exp $ */
3 /*
4  * FreeBSD/CAM specific routines for LSI '909 FC  adapters.
5  * FreeBSD Version.
6  *
7  * Copyright (c)  2000, 2001 by Greg Ansley
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 immediately at the beginning of the file, without modification,
14  *    this list of conditions, and the following disclaimer.
15  * 2. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*
31  * Additional Copyright (c) 2002 by Matthew Jacob under same license.
32  */
33
34 #include "mpt_freebsd.h"
35
36 static void mpt_poll(struct cam_sim *);
37 static timeout_t mpttimeout;
38 static timeout_t mpttimeout2;
39 static void mpt_action(struct cam_sim *, union ccb *);
40 static int mpt_setwidth(mpt_softc_t *, int, int);
41 static int mpt_setsync(mpt_softc_t *, int, int, int);
42
43 void
44 mpt_cam_attach(mpt_softc_t *mpt)
45 {
46         struct cam_devq *devq;
47         struct cam_sim *sim;
48         int maxq;
49
50         mpt->bus = 0;
51         maxq = (mpt->mpt_global_credits < MPT_MAX_REQUESTS(mpt))?
52             mpt->mpt_global_credits : MPT_MAX_REQUESTS(mpt);
53
54
55         /*
56          * Create the device queue for our SIM(s).
57          */
58         
59         devq = cam_simq_alloc(maxq);
60         if (devq == NULL) {
61                 return;
62         }
63
64         /*
65          * Construct our SIM entry.
66          */
67         sim = cam_sim_alloc(mpt_action, mpt_poll, "mpt", mpt,
68             mpt->unit, 1, maxq, devq);
69         if (sim == NULL) {
70                 cam_simq_free(devq);
71                 return;
72         }
73
74         /*
75          * Register exactly the bus.
76          */
77
78         if (xpt_bus_register(sim, 0) != CAM_SUCCESS) {
79                 cam_sim_free(sim, TRUE);
80                 return;
81         }
82
83         if (xpt_create_path(&mpt->path, NULL, cam_sim_path(sim),
84             CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
85                 xpt_bus_deregister(cam_sim_path(sim));
86                 cam_sim_free(sim, TRUE);
87                 return;
88         }
89         mpt->sim = sim;
90 }
91
92 void
93 mpt_cam_detach(mpt_softc_t *mpt)
94 {
95         if (mpt->sim != NULL) {
96                 xpt_free_path(mpt->path);
97                 xpt_bus_deregister(cam_sim_path(mpt->sim));
98                 cam_sim_free(mpt->sim, TRUE);
99                 mpt->sim = NULL;
100         }
101 }
102
103 /* This routine is used after a system crash to dump core onto the
104  * swap device.
105  */
106 static void
107 mpt_poll(struct cam_sim *sim)
108 {
109         mpt_softc_t *mpt = (mpt_softc_t *) cam_sim_softc(sim);
110         MPT_LOCK(mpt);
111         mpt_intr(mpt);
112         MPT_UNLOCK(mpt);
113 }
114
115 /*
116  * This routine is called if the 9x9 does not return completion status
117  * for a command after a CAM specified time.
118  */
119 static void
120 mpttimeout(void *arg)
121 {
122         request_t *req;
123         union ccb *ccb = arg;
124         u_int32_t oseq;
125         mpt_softc_t *mpt;
126
127         mpt = ccb->ccb_h.ccb_mpt_ptr;
128         MPT_LOCK(mpt);
129         req = ccb->ccb_h.ccb_req_ptr;
130         oseq = req->sequence;
131         mpt->timeouts++;
132         if (mpt_intr(mpt)) {
133                 if (req->sequence != oseq) {
134                         device_printf(mpt->dev, "bullet missed in timeout\n");
135                         MPT_UNLOCK(mpt);
136                         return;
137                 }
138                 device_printf(mpt->dev, "bullet U-turned in timeout: got us\n");
139         }
140         device_printf(mpt->dev,
141             "time out on request index = 0x%02x sequence = 0x%08x\n",
142             req->index, req->sequence);
143         mpt_check_doorbell(mpt);
144         device_printf(mpt->dev, "Status %08X; Mask %08X; Doorbell %08X\n",
145                 mpt_read(mpt, MPT_OFFSET_INTR_STATUS),
146                 mpt_read(mpt, MPT_OFFSET_INTR_MASK),
147                 mpt_read(mpt, MPT_OFFSET_DOORBELL) );
148         printf("request state %s\n", mpt_req_state(req->debug)); 
149         if (ccb != req->ccb) {
150                 printf("time out: ccb %p != req->ccb %p\n",
151                         ccb,req->ccb);
152         }
153         mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf);
154         req->debug = REQ_TIMEOUT;
155         req->ccb = NULL;
156         req->link.sle_next = (void *) mpt;
157         (void) timeout(mpttimeout2, (caddr_t)req, hz / 10);
158         ccb->ccb_h.status = CAM_CMD_TIMEOUT;
159         ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
160         mpt->outofbeer = 0;
161         MPTLOCK_2_CAMLOCK(mpt);
162         xpt_done(ccb);
163         CAMLOCK_2_MPTLOCK(mpt);
164         MPT_UNLOCK(mpt);
165 }
166
167 static void
168 mpttimeout2(void *arg)
169 {
170         request_t *req = arg;
171         if (req->debug == REQ_TIMEOUT) {
172                 mpt_softc_t *mpt = (mpt_softc_t *) req->link.sle_next;
173                 MPT_LOCK(mpt);
174                 mpt_free_request(mpt, req);
175                 MPT_UNLOCK(mpt);
176         }
177 }
178
179 /*
180  * Callback routine from "bus_dmamap_load" or in simple case called directly.
181  *
182  * Takes a list of physical segments and builds the SGL for SCSI IO command
183  * and forwards the commard to the IOC after one last check that CAM has not
184  * aborted the transaction.
185  */
186 static void
187 mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
188 {
189         request_t *req;
190         union ccb *ccb;
191         mpt_softc_t *mpt;
192         MSG_SCSI_IO_REQUEST *mpt_req;
193         SGE_SIMPLE32 *se;
194
195         req = (request_t *)arg;
196         ccb = req->ccb;
197
198         mpt = ccb->ccb_h.ccb_mpt_ptr;
199         req = ccb->ccb_h.ccb_req_ptr;
200         mpt_req = req->req_vbuf;
201
202         if (error == 0 && nseg > MPT_SGL_MAX) {
203                 error = EFBIG;
204         }
205
206         if (error != 0) {
207                 if (error != EFBIG)
208                         device_printf(mpt->dev, "bus_dmamap_load returned %d\n",
209                             error);
210                 if (ccb->ccb_h.status == CAM_REQ_INPROG) {
211                         xpt_freeze_devq(ccb->ccb_h.path, 1);
212                         ccb->ccb_h.status = CAM_DEV_QFRZN;
213                         if (error == EFBIG)
214                                 ccb->ccb_h.status |= CAM_REQ_TOO_BIG;
215                         else
216                                 ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
217                 }
218                 ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
219                 xpt_done(ccb);
220                 CAMLOCK_2_MPTLOCK(mpt);
221                 mpt_free_request(mpt, req);
222                 MPTLOCK_2_CAMLOCK(mpt);
223                 return;
224         }
225         
226         if (nseg > MPT_NSGL_FIRST(mpt)) {
227                 int i, nleft = nseg;
228                 u_int32_t flags;
229                 bus_dmasync_op_t op;
230                 SGE_CHAIN32 *ce;
231
232                 mpt_req->DataLength = ccb->csio.dxfer_len;
233                 flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
234                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
235                         flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
236
237                 se = (SGE_SIMPLE32 *) &mpt_req->SGL;
238                 for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1; i++, se++, dm_segs++) {
239                         u_int32_t tf;
240
241                         bzero(se, sizeof (*se));
242                         se->Address = dm_segs->ds_addr;
243                         MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
244                         tf = flags;
245                         if (i == MPT_NSGL_FIRST(mpt) - 2) {
246                                 tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
247                         }
248                         MPI_pSGE_SET_FLAGS(se, tf);
249                         nleft -= 1;
250                 }
251
252                 /*
253                  * Tell the IOC where to find the first chain element
254                  */
255                 mpt_req->ChainOffset = ((char *)se - (char *)mpt_req) >> 2;
256
257                 /*
258                  * Until we're finished with all segments...
259                  */
260                 while (nleft) {
261                         int ntodo;
262                         /*
263                          * Construct the chain element that point to the
264                          * next segment.
265                          */
266                         ce = (SGE_CHAIN32 *) se++;
267                         if (nleft > MPT_NSGL(mpt)) {
268                                 ntodo = MPT_NSGL(mpt) - 1;
269                                 ce->NextChainOffset = (MPT_RQSL(mpt) -
270                                     sizeof (SGE_SIMPLE32)) >> 2;
271                         } else {
272                                 ntodo = nleft;
273                                 ce->NextChainOffset = 0;
274                         }
275                         ce->Length = ntodo * sizeof (SGE_SIMPLE32);
276                         ce->Address = req->req_pbuf +
277                             ((char *)se - (char *)mpt_req);
278                         ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
279                         for (i = 0; i < ntodo; i++, se++, dm_segs++) {
280                                 u_int32_t tf;
281
282                                 bzero(se, sizeof (*se));
283                                 se->Address = dm_segs->ds_addr;
284                                 MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
285                                 tf = flags;
286                                 if (i == ntodo - 1) {
287                                         tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
288                                         if (ce->NextChainOffset == 0) {
289                                                 tf |=
290                                                     MPI_SGE_FLAGS_END_OF_LIST |
291                                                     MPI_SGE_FLAGS_END_OF_BUFFER;
292                                         }
293                                 }
294                                 MPI_pSGE_SET_FLAGS(se, tf);
295                                 nleft -= 1;
296                         }
297
298                 }
299
300                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
301                         op = BUS_DMASYNC_PREREAD;
302                 else
303                         op = BUS_DMASYNC_PREWRITE;
304                 if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) {
305                         bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op);
306                 }
307         } else if (nseg > 0) {
308                 int i;
309                 u_int32_t flags;
310                 bus_dmasync_op_t op;
311
312                 mpt_req->DataLength = ccb->csio.dxfer_len;
313                 flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
314                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
315                         flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
316
317                 /* Copy the segments into our SG list */
318                 se = (SGE_SIMPLE32 *) &mpt_req->SGL;
319                 for (i = 0; i < nseg; i++, se++, dm_segs++) {
320                         u_int32_t tf;
321
322                         bzero(se, sizeof (*se));
323                         se->Address = dm_segs->ds_addr;
324                         MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
325                         tf = flags;
326                         if (i == nseg - 1) {
327                                 tf |=
328                                     MPI_SGE_FLAGS_LAST_ELEMENT |
329                                     MPI_SGE_FLAGS_END_OF_BUFFER |
330                                     MPI_SGE_FLAGS_END_OF_LIST;
331                         }
332                         MPI_pSGE_SET_FLAGS(se, tf);
333                 }
334
335                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
336                         op = BUS_DMASYNC_PREREAD;
337                 else
338                         op = BUS_DMASYNC_PREWRITE;
339                 if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) {
340                         bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op);
341                 }
342         } else {
343                 se = (SGE_SIMPLE32 *) &mpt_req->SGL;
344                 /*
345                  * No data to transfer so we just make a single simple SGL
346                  * with zero length.
347                  */
348                 MPI_pSGE_SET_FLAGS(se,
349                     (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
350                     MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
351         }
352
353         /*
354          * Last time we need to check if this CCB needs to be aborted.
355          */
356         if (ccb->ccb_h.status != CAM_REQ_INPROG) {
357                 if (nseg && (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)
358                         bus_dmamap_unload(mpt->buffer_dmat, req->dmap);
359                 CAMLOCK_2_MPTLOCK(mpt);
360                 mpt_free_request(mpt, req);
361                 MPTLOCK_2_CAMLOCK(mpt);
362                 xpt_done(ccb);
363                 return;
364         }
365
366         ccb->ccb_h.status |= CAM_SIM_QUEUED;
367         MPTLOCK_2_CAMLOCK(mpt);
368         if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
369                 ccb->ccb_h.timeout_ch =
370                         timeout(mpttimeout, (caddr_t)ccb,
371                                 (ccb->ccb_h.timeout * hz) / 1000);
372         } else {
373                 callout_handle_init(&ccb->ccb_h.timeout_ch);
374         }
375         if (mpt->verbose > 1)
376                 mpt_print_scsi_io_request(mpt_req);
377         mpt_send_cmd(mpt, req);
378         MPTLOCK_2_CAMLOCK(mpt);
379 }
380
381 static void
382 mpt_start(union ccb *ccb)
383 {
384         request_t *req;
385         struct mpt_softc *mpt;
386         MSG_SCSI_IO_REQUEST *mpt_req;
387         struct ccb_scsiio *csio = &ccb->csio;
388         struct ccb_hdr *ccbh = &ccb->ccb_h;
389
390         /* Get the pointer for the physical addapter */
391         mpt = ccb->ccb_h.ccb_mpt_ptr;
392
393         CAMLOCK_2_MPTLOCK(mpt);
394         /* Get a request structure off the free list */
395         if ((req = mpt_get_request(mpt)) == NULL) {
396                 if (mpt->outofbeer == 0) {
397                         mpt->outofbeer = 1;
398                         xpt_freeze_simq(mpt->sim, 1);
399                         if (mpt->verbose > 1) {
400                                 device_printf(mpt->dev, "FREEZEQ\n");
401                         }
402                 }
403                 MPTLOCK_2_CAMLOCK(mpt);
404                 ccb->ccb_h.status = CAM_REQUEUE_REQ;
405                 xpt_done(ccb);
406                 return;
407         }
408         MPTLOCK_2_CAMLOCK(mpt);
409
410         /* Link the ccb and the request structure so we can find */
411         /* the other knowing either the request or the ccb               */
412         req->ccb = ccb;
413         ccb->ccb_h.ccb_req_ptr = req;
414
415         /* Now we build the command for the IOC */
416         mpt_req = req->req_vbuf;
417         bzero(mpt_req, sizeof *mpt_req);
418
419         mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
420         mpt_req->Bus = mpt->bus;
421
422         mpt_req->SenseBufferLength =
423                 (csio->sense_len < MPT_SENSE_SIZE) ?
424                  csio->sense_len : MPT_SENSE_SIZE;
425
426         /* We use the message context to find the request structure when we */
427         /* Get the command competion interrupt from the FC IOC.                         */
428         mpt_req->MsgContext = req->index;
429
430         /* Which physical device to do the I/O on */
431         mpt_req->TargetID = ccb->ccb_h.target_id;
432         mpt_req->LUN[1] = ccb->ccb_h.target_lun;
433
434         /* Set the direction of the transfer */
435         if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
436                 mpt_req->Control = MPI_SCSIIO_CONTROL_READ;
437         else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
438                 mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE;
439         else
440                 mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER;
441
442         if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
443                 switch(ccb->csio.tag_action) {
444                 case MSG_HEAD_OF_Q_TAG:
445                         mpt_req->Control |= MPI_SCSIIO_CONTROL_HEADOFQ;
446                         break;
447                 case MSG_ACA_TASK:
448                         mpt_req->Control |= MPI_SCSIIO_CONTROL_ACAQ;
449                         break;
450                 case MSG_ORDERED_Q_TAG:
451                         mpt_req->Control |= MPI_SCSIIO_CONTROL_ORDEREDQ;
452                         break;
453                 case MSG_SIMPLE_Q_TAG:
454                 default:
455                         mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ;
456                         break;
457                 }
458         } else {
459                 if (mpt->is_fc)
460                         mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ;
461                 else
462                         mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED;
463         }
464
465         if (mpt->is_fc == 0) {
466                 if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
467                         mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT;
468                 }
469         }
470
471         /* Copy the scsi command block into place */
472         if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0)
473                 bcopy(csio->cdb_io.cdb_ptr, mpt_req->CDB, csio->cdb_len);
474         else
475                 bcopy(csio->cdb_io.cdb_bytes, mpt_req->CDB, csio->cdb_len);
476
477         mpt_req->CDBLength = csio->cdb_len;
478         mpt_req->DataLength = csio->dxfer_len;
479         mpt_req->SenseBufferLowAddr = req->sense_pbuf;
480
481         /*
482          * If we have any data to send with this command,
483          * map it into bus space.
484          */
485
486         if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
487                 if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
488                         /*
489                          * We've been given a pointer to a single buffer.
490                          */
491                         if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
492                                 /*
493                                  * Virtual address that needs to translated into
494                                  * one or more physical pages.
495                                  */
496                                 int error;
497
498                                 error = bus_dmamap_load(mpt->buffer_dmat,
499                                     req->dmap, csio->data_ptr, csio->dxfer_len,
500                                     mpt_execute_req, req, 0);
501                                 if (error == EINPROGRESS) {
502                                         /*
503                                          * So as to maintain ordering,
504                                          * freeze the controller queue
505                                          * until our mapping is
506                                          * returned.
507                                          */
508                                         xpt_freeze_simq(mpt->sim, 1);
509                                         ccbh->status |= CAM_RELEASE_SIMQ;
510                                 }
511                         } else {
512                                 /*
513                                  * We have been given a pointer to single
514                                  * physical buffer.
515                                  */
516                                 struct bus_dma_segment seg;
517                                 seg.ds_addr = (bus_addr_t)csio->data_ptr;
518                                 seg.ds_len = csio->dxfer_len;
519                                 mpt_execute_req(req, &seg, 1, 0);
520                         }
521                 } else {
522                         /*
523                          * We have been given a list of addresses.
524                          * These case could be easily done but they are not
525                          * currently generated by the CAM subsystem so there
526                          * is no point in wasting the time right now.
527                          */
528                         struct bus_dma_segment *segs;
529                         if ((ccbh->flags & CAM_SG_LIST_PHYS) == 0) {
530                                 mpt_execute_req(req, NULL, 0, EFAULT);
531                         } else {
532                                 /* Just use the segments provided */
533                                 segs = (struct bus_dma_segment *)csio->data_ptr;
534                                 mpt_execute_req(req, segs, csio->sglist_cnt,
535                                     (csio->sglist_cnt < MPT_SGL_MAX)?
536                                     0 : EFBIG);
537                         }
538                 }
539         } else {
540                 mpt_execute_req(req, NULL, 0, 0);
541         }
542 }
543
544 static int
545 mpt_bus_reset(union ccb *ccb)
546 {
547         int error;
548         request_t *req;
549         mpt_softc_t *mpt;
550         MSG_SCSI_TASK_MGMT *reset_req;
551
552         /* Get the pointer for the physical adapter */
553         mpt = ccb->ccb_h.ccb_mpt_ptr;
554
555         /* Get a request structure off the free list */
556         if ((req = mpt_get_request(mpt)) == NULL) {
557                 return (CAM_REQUEUE_REQ);
558         }
559
560         /* Link the ccb and the request structure so we can find */
561         /* the other knowing either the request or the ccb               */
562         req->ccb = ccb;
563         ccb->ccb_h.ccb_req_ptr = req;
564
565         reset_req = req->req_vbuf;
566         bzero(reset_req, sizeof *reset_req);
567
568         reset_req->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
569         reset_req->MsgContext = req->index;
570         reset_req->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
571         if (mpt->is_fc) {
572                 /*
573                  * Should really be TARGET_RESET_OPTION
574                  */
575                 reset_req->MsgFlags =
576                     MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION;
577         }
578         /* Which physical device Reset */
579         reset_req->TargetID = ccb->ccb_h.target_id;
580         reset_req->LUN[1] = ccb->ccb_h.target_lun;
581
582         ccb->ccb_h.status |= CAM_SIM_QUEUED;
583
584         error = mpt_send_handshake_cmd(mpt,
585             sizeof (MSG_SCSI_TASK_MGMT), reset_req);
586         if (error) {
587                 device_printf(mpt->dev,
588                     "mpt_bus_reset: mpt_send_handshake return %d\n", error);
589                 return (CAM_REQ_CMP_ERR);
590         } else {
591                 return (CAM_REQ_CMP);
592         }
593 }
594
595 /*
596  * Process an asynchronous event from the IOC.
597  */
598 static void mpt_ctlop(mpt_softc_t *, void *, u_int32_t);
599 static void mpt_event_notify_reply(mpt_softc_t *mpt, MSG_EVENT_NOTIFY_REPLY *);
600
601 void
602 mpt_ctlop(mpt_softc_t *mpt, void *vmsg, u_int32_t reply)
603 {
604         MSG_DEFAULT_REPLY *dmsg = vmsg;
605
606         if (dmsg->Function == MPI_FUNCTION_EVENT_NOTIFICATION) {
607                 mpt_event_notify_reply(mpt, vmsg);
608                 mpt_free_reply(mpt, (reply << 1));
609         } else if (dmsg->Function == MPI_FUNCTION_EVENT_ACK) {
610                 mpt_free_reply(mpt, (reply << 1));
611         } else if (dmsg->Function == MPI_FUNCTION_PORT_ENABLE) {
612                 MSG_PORT_ENABLE_REPLY *msg = vmsg;
613                 int index = msg->MsgContext & ~0x80000000;
614                 if (mpt->verbose > 1) {
615                         device_printf(mpt->dev, "enable port reply idx %d\n",
616                             index);
617                 }
618                 if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) {
619                         request_t *req = &mpt->request_pool[index];
620                         req->debug = REQ_DONE;
621                 }
622                 mpt_free_reply(mpt, (reply << 1));
623         } else if (dmsg->Function == MPI_FUNCTION_CONFIG) {
624                 MSG_CONFIG_REPLY *msg = vmsg;
625                 int index = msg->MsgContext & ~0x80000000;
626                 if (index >= 0 && index < MPT_MAX_REQUESTS(mpt)) {
627                         request_t *req = &mpt->request_pool[index];
628                         req->debug = REQ_DONE;
629                         req->sequence = reply;
630                 } else {
631                         mpt_free_reply(mpt, (reply << 1));
632                 }
633         } else {
634                 device_printf(mpt->dev, "unknown mpt_ctlop: %x\n",
635                     dmsg->Function);
636         }
637 }
638
639 static void
640 mpt_event_notify_reply(mpt_softc_t *mpt, MSG_EVENT_NOTIFY_REPLY *msg)
641 {
642         switch(msg->Event) {
643         case MPI_EVENT_LOG_DATA:
644                 /* Some error occured that LSI wants logged */
645                 device_printf(mpt->dev,
646                     "\tEvtLogData: IOCLogInfo: 0x%08x\n",
647                     msg->IOCLogInfo);
648                 device_printf(mpt->dev, "\tEvtLogData: Event Data:");
649                 {
650                         int i;
651                         for (i = 0; i < msg->EventDataLength; i++) {
652                                 device_printf(mpt->dev,
653                                     "  %08X", msg->Data[i]);
654                         }
655                 }
656                 device_printf(mpt->dev, "\n");
657                 break;
658
659         case MPI_EVENT_UNIT_ATTENTION:
660                 device_printf(mpt->dev,
661                     "Bus: 0x%02x TargetID: 0x%02x\n",
662                     (msg->Data[0] >> 8) & 0xff, msg->Data[0] & 0xff);
663                 break;
664
665         case MPI_EVENT_IOC_BUS_RESET:
666                 /* We generated a bus reset */
667                 device_printf(mpt->dev, "IOC Bus Reset Port: %d\n",
668                     (msg->Data[0] >> 8) & 0xff);
669                 break;
670
671         case MPI_EVENT_EXT_BUS_RESET:
672                 /* Someone else generated a bus reset */
673                 device_printf(mpt->dev, "Ext Bus Reset\n");
674                 /*
675                  * These replies don't return EventData like the MPI
676                  * spec says they do
677                  */     
678 /*              xpt_async(AC_BUS_RESET, path, NULL);  */
679                 break;
680
681         case MPI_EVENT_RESCAN:
682                 /*
683                  * In general this means a device has been added
684                  * to the loop.
685                  */
686                 device_printf(mpt->dev,
687                     "Rescan Port: %d\n", (msg->Data[0] >> 8) & 0xff);
688 /*              xpt_async(AC_FOUND_DEVICE, path, NULL);  */
689                 break;
690
691         case MPI_EVENT_LINK_STATUS_CHANGE:
692                 device_printf(mpt->dev, "Port %d: LinkState: %s\n",
693                     (msg->Data[1] >> 8) & 0xff,
694                     ((msg->Data[0] & 0xff) == 0)?  "Failed" : "Active");
695                 break;
696
697         case MPI_EVENT_LOOP_STATE_CHANGE:
698                 switch ((msg->Data[0] >> 16) & 0xff) {
699                 case 0x01:
700                         device_printf(mpt->dev,
701                             "Port 0x%x: FC LinkEvent: LIP(%02X,%02X) (Loop Initialization)\n",
702                             (msg->Data[1] >> 8) & 0xff,
703                             (msg->Data[0] >> 8) & 0xff,
704                             (msg->Data[0]     ) & 0xff);
705                         switch ((msg->Data[0] >> 8) & 0xff) {
706                         case 0xF7:
707                                 if ((msg->Data[0] & 0xff) == 0xF7) {
708                                         printf("Device needs AL_PA\n");
709                                 } else {
710                                         printf("Device %02X doesn't like FC performance\n", 
711                                                                         msg->Data[0] & 0xFF);
712                                 }
713                                 break;
714                         case 0xF8:
715                                 if ((msg->Data[0] & 0xff) == 0xF7) {
716                                         printf("Device had loop failure at its receiver prior to acquiring AL_PA\n");
717                                 } else {
718                                         printf("Device %02X detected loop failure at its receiver\n", 
719                                                                         msg->Data[0] & 0xFF);
720                                 }
721                                 break;
722                         default:
723                                 printf("Device %02X requests that device %02X reset itself\n", 
724                                         msg->Data[0] & 0xFF,
725                                         (msg->Data[0] >> 8) & 0xFF);
726                                 break;
727                         }
728                         break;
729                 case 0x02:
730                         device_printf(mpt->dev, "Port 0x%x: FC LinkEvent: LPE(%02X,%02X) (Loop Port Enable)\n",
731                                 (msg->Data[1] >> 8) & 0xff, /* Port */
732                                 (msg->Data[0] >>  8) & 0xff, /* Character 3 */
733                                 (msg->Data[0]      ) & 0xff  /* Character 4 */
734                                 );
735                         break;
736                 case 0x03:
737                         device_printf(mpt->dev, "Port 0x%x: FC LinkEvent: LPB(%02X,%02X) (Loop Port Bypass)\n",
738                                 (msg->Data[1] >> 8) & 0xff, /* Port */
739                         (msg->Data[0] >> 8) & 0xff, /* Character 3 */
740                         (msg->Data[0]     ) & 0xff  /* Character 4 */
741                                 );
742                         break;
743                 default:
744                         device_printf(mpt->dev, "Port 0x%x: FC LinkEvent: Unknown FC event (%02X %02X %02X)\n",
745                                 (msg->Data[1] >> 8) & 0xff, /* Port */
746                                 (msg->Data[0] >> 16) & 0xff, /* Event */
747                                 (msg->Data[0] >>  8) & 0xff, /* Character 3 */
748                                 (msg->Data[0]      ) & 0xff  /* Character 4 */
749                                 );
750                 }
751                 break;
752
753         case MPI_EVENT_LOGOUT:
754                 device_printf(mpt->dev, "FC Logout Port: %d N_PortID: %02X\n",
755                         (msg->Data[1] >> 8) & 0xff,
756                         msg->Data[0]);
757                 break;
758         case MPI_EVENT_EVENT_CHANGE:
759                 /* This is just an acknowledgement of our 
760                    mpt_send_event_request */
761                 break;
762         default:
763                 device_printf(mpt->dev, "Unknown event %X\n", msg->Event);
764         }
765         if (msg->AckRequired) {
766                 MSG_EVENT_ACK *ackp;
767                 request_t *req;
768                 if ((req = mpt_get_request(mpt)) == NULL) {
769                         panic("unable to get request to acknowledge notify");
770                 }
771                 ackp = (MSG_EVENT_ACK *) req->req_vbuf;
772                 bzero(ackp, sizeof *ackp);
773                 ackp->Function = MPI_FUNCTION_EVENT_ACK;
774                 ackp->Event = msg->Event;
775                 ackp->EventContext = msg->EventContext;
776                 ackp->MsgContext = req->index | 0x80000000;
777                 mpt_check_doorbell(mpt);
778                 mpt_send_cmd(mpt, req);
779         }
780 }
781
782 void
783 mpt_done(mpt_softc_t *mpt, u_int32_t reply)
784 {
785         int index;
786         request_t *req;
787         union ccb *ccb;
788         MSG_REQUEST_HEADER *mpt_req;
789         MSG_SCSI_IO_REPLY *mpt_reply;
790
791         index = -1; /* Shutup the complier */
792
793         if ((reply & MPT_CONTEXT_REPLY) == 0) {
794                 /* context reply */
795                 mpt_reply = NULL;
796                 index = reply & MPT_CONTEXT_MASK;
797         } else {
798                 unsigned *pReply;
799
800                 bus_dmamap_sync(mpt->reply_dmat, mpt->reply_dmap,
801                     BUS_DMASYNC_POSTREAD);
802                 /* address reply (Error) */
803                 mpt_reply = MPT_REPLY_PTOV(mpt, reply);
804                 if (mpt->verbose > 1) {
805                         pReply = (unsigned *) mpt_reply;
806                         device_printf(mpt->dev, "Address Reply (index %u)\n",
807                             mpt_reply->MsgContext & 0xffff);
808                         device_printf(mpt->dev, "%08X %08X %08X %08X\n",
809                             pReply[0], pReply[1], pReply[2], pReply[3]);
810                         device_printf(mpt->dev, "%08X %08X %08X %08X\n",
811                             pReply[4], pReply[5], pReply[6], pReply[7]);
812                         device_printf(mpt->dev, "%08X %08X %08X %08X\n\n",
813                             pReply[8], pReply[9], pReply[10], pReply[11]);
814                 }
815                 index = mpt_reply->MsgContext;
816         }
817
818         /*
819          * Address reply with MessageContext high bit set
820          * This is most likely a notify message so we try
821          * to process it then free it
822          */
823         if ((index & 0x80000000) != 0) {
824                 if (mpt_reply != NULL) {
825                         mpt_ctlop(mpt, mpt_reply, reply);
826                 } else {
827                         device_printf(mpt->dev,
828                             "mpt_done: index 0x%x, NULL reply\n", index);
829                 }
830                 return;
831         }
832
833         /* Did we end up with a valid index into the table? */
834         if (index < 0 || index >= MPT_MAX_REQUESTS(mpt)) {
835                 printf("mpt_done: invalid index (%x) in reply\n", index);
836                 return;
837         }
838
839         req = &mpt->request_pool[index];
840
841         /* Make sure memory hasn't been trashed */
842         if (req->index != index) {
843                 printf("mpt_done: corrupted request struct");
844                 return;
845         }
846
847         /* Short cut for task management replys; nothing more for us to do */
848         mpt_req = req->req_vbuf;
849         if (mpt_req->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
850                 if (mpt->verbose > 1) {
851                         device_printf(mpt->dev, "mpt_done: TASK MGMT\n");
852                 }
853                 goto done;
854         }
855
856         if (mpt_req->Function == MPI_FUNCTION_PORT_ENABLE) {
857                 goto done;
858         }
859
860         /*
861          * At this point it better be a SCSI IO command, but don't
862          * crash if it isn't
863          */
864         if (mpt_req->Function != MPI_FUNCTION_SCSI_IO_REQUEST)  {
865                 goto done;
866         }
867
868         /* Recover the CAM control block from the request structure */
869         ccb = req->ccb;
870
871         /* Can't have had a SCSI command with out a CAM control block */
872         if (ccb == NULL || (ccb->ccb_h.status & CAM_SIM_QUEUED) == 0) {
873                 device_printf(mpt->dev,
874                     "mpt_done: corrupted ccb, index = 0x%02x seq = 0x%08x",
875                     req->index, req->sequence);
876                 printf(" request state %s\nmpt_request:\n",
877                     mpt_req_state(req->debug)); 
878                 mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req->req_vbuf);
879
880                 if (mpt_reply != NULL) {
881                         printf("\nmpt_done: reply:\n"); 
882                         mpt_print_reply(MPT_REPLY_PTOV(mpt, reply));
883                 } else {
884                         printf("\nmpt_done: context reply: 0x%08x\n", reply); 
885                 }
886                 goto done;
887         }
888
889         untimeout(mpttimeout, ccb, ccb->ccb_h.timeout_ch);
890
891         if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
892                 bus_dmasync_op_t op;
893
894                 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
895                         op = BUS_DMASYNC_POSTREAD;
896                 } else {
897                         op = BUS_DMASYNC_POSTWRITE;
898                 }
899                 bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op);
900                 bus_dmamap_unload(mpt->buffer_dmat, req->dmap);
901         }
902         ccb->csio.resid = 0;
903
904         if (mpt_reply == NULL) {
905                 /* Context reply; report that the command was successfull */
906                 ccb->ccb_h.status = CAM_REQ_CMP;
907                 ccb->csio.scsi_status = SCSI_STATUS_OK;
908                 ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
909                 if (mpt->outofbeer) {
910                         ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
911                         mpt->outofbeer = 0;
912                         if (mpt->verbose > 1) {
913                                 device_printf(mpt->dev, "THAWQ\n");
914                         }
915                 }
916                 MPTLOCK_2_CAMLOCK(mpt);
917                 xpt_done(ccb);
918                 CAMLOCK_2_MPTLOCK(mpt);
919                 goto done;
920         }
921
922         ccb->csio.scsi_status = mpt_reply->SCSIStatus;
923         switch(mpt_reply->IOCStatus) {
924         case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
925                 ccb->ccb_h.status = CAM_DATA_RUN_ERR;
926                 break;
927
928         case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
929                 /*
930                  * Yikes, Tagged queue full comes through this path!
931                  *
932                  * So we'll change it to a status error and anything
933                  * that returns status should probably be a status 
934                  * error as well.
935                  */
936                 ccb->csio.resid =
937                     ccb->csio.dxfer_len - mpt_reply->TransferCount;
938                 if (mpt_reply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) {
939                         ccb->ccb_h.status = CAM_DATA_RUN_ERR;
940                         break;
941                 }
942 #if     0
943 device_printf(mpt->dev, "underrun, scsi status is %x\n", ccb->csio.scsi_status);
944                 ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
945 #endif
946                 /* Fall through */
947         case MPI_IOCSTATUS_SUCCESS:
948         case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:
949                 switch (ccb->csio.scsi_status) {
950                 case SCSI_STATUS_OK:
951                         ccb->ccb_h.status = CAM_REQ_CMP;
952                         break;
953                 default:
954                         ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
955                         break;
956                 }
957                 break;
958         case MPI_IOCSTATUS_BUSY:
959         case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES:
960                 ccb->ccb_h.status = CAM_BUSY;
961                 break;
962
963         case MPI_IOCSTATUS_SCSI_INVALID_BUS:
964         case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
965         case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
966                 ccb->ccb_h.status = CAM_DEV_NOT_THERE;
967                 break;
968
969         case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
970                 ccb->ccb_h.status = CAM_DATA_RUN_ERR;
971                 break;
972
973         case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
974         case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
975                 ccb->ccb_h.status =  CAM_UNCOR_PARITY;
976                 break;
977
978         case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
979                 ccb->ccb_h.status = CAM_REQ_CMP;
980                 break;
981
982         case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
983                 ccb->ccb_h.status = CAM_UA_TERMIO;
984                 break;
985
986         case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
987                 ccb->ccb_h.status = CAM_REQ_TERMIO;
988                 break;
989
990         case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
991                 ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 
992                 break;
993
994         default:
995                 ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
996                 break;
997         }
998
999         if ((mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) != 0) {
1000                 if (ccb->ccb_h.flags & (CAM_SENSE_PHYS | CAM_SENSE_PTR)) {
1001                         ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
1002                 } else {
1003                         ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1004                         ccb->csio.sense_resid = mpt_reply->SenseCount;
1005                         bcopy(req->sense_vbuf, &ccb->csio.sense_data,
1006                             ccb->csio.sense_len);
1007                 }
1008         } else if (mpt_reply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
1009                 ccb->ccb_h.status &= ~CAM_STATUS_MASK;
1010                 ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
1011         }
1012
1013         if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1014                 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
1015                         ccb->ccb_h.status |= CAM_DEV_QFRZN;
1016                         xpt_freeze_devq(ccb->ccb_h.path, 1);
1017                 }
1018         }
1019
1020
1021         ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1022         if (mpt->outofbeer) {
1023                 ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
1024                 mpt->outofbeer = 0;
1025                 if (mpt->verbose > 1) {
1026                         device_printf(mpt->dev, "THAWQ\n");
1027                 }
1028         }
1029         MPTLOCK_2_CAMLOCK(mpt);
1030         xpt_done(ccb);
1031         CAMLOCK_2_MPTLOCK(mpt);
1032
1033 done:
1034         /* If IOC done with this request free it up */
1035         if (mpt_reply == NULL || (mpt_reply->MsgFlags & 0x80) == 0)
1036                 mpt_free_request(mpt, req);
1037
1038         /* If address reply; give the buffer back to the IOC */
1039         if (mpt_reply != NULL)
1040                 mpt_free_reply(mpt, (reply << 1));
1041 }
1042
1043 static void
1044 mpt_action(struct cam_sim *sim, union ccb *ccb)
1045 {
1046         int  tgt, error;
1047         mpt_softc_t *mpt;
1048         struct ccb_trans_settings *cts;
1049
1050         CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("mpt_action\n"));
1051
1052         mpt = (mpt_softc_t *)cam_sim_softc(sim);
1053
1054         ccb->ccb_h.ccb_mpt_ptr = mpt;
1055
1056         switch (ccb->ccb_h.func_code) {
1057         case XPT_RESET_BUS:
1058                 if (mpt->verbose > 1)
1059                     device_printf(mpt->dev, "XPT_RESET_BUS\n");
1060                 CAMLOCK_2_MPTLOCK(mpt);
1061                 error = mpt_bus_reset(ccb);
1062                 switch (error) {
1063                 case CAM_REQ_INPROG:
1064                         MPTLOCK_2_CAMLOCK(mpt);
1065                         break;
1066                 case CAM_REQUEUE_REQ:
1067                         if (mpt->outofbeer == 0) {
1068                                 mpt->outofbeer = 1;
1069                                 xpt_freeze_simq(sim, 1);
1070                                 if (mpt->verbose > 1) {
1071                                         device_printf(mpt->dev, "FREEZEQ\n");
1072                                 }
1073                         }
1074                         ccb->ccb_h.status = CAM_REQUEUE_REQ;
1075                         MPTLOCK_2_CAMLOCK(mpt);
1076                         xpt_done(ccb);
1077                         break;
1078
1079                 case CAM_REQ_CMP:
1080                         ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1081                         ccb->ccb_h.status |= CAM_REQ_CMP;
1082                         if (mpt->outofbeer) {
1083                                 ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
1084                                 mpt->outofbeer = 0;
1085                                 if (mpt->verbose > 1) {
1086                                         device_printf(mpt->dev, "THAWQ\n");
1087                                 }
1088                         }
1089                         MPTLOCK_2_CAMLOCK(mpt);
1090                         xpt_done(ccb);
1091                         break;
1092
1093                 default:
1094                         ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1095                         MPTLOCK_2_CAMLOCK(mpt);
1096                         xpt_done(ccb);
1097                 }
1098                 break;
1099                 
1100         case XPT_SCSI_IO:       /* Execute the requested I/O operation */
1101                 /*
1102                  * Do a couple of preliminary checks...
1103                  */
1104                 if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1105                         if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) {
1106                                 ccb->ccb_h.status = CAM_REQ_INVALID;
1107                                 xpt_done(ccb);
1108                                 break;
1109                         }
1110                 }
1111                 /* Max supported CDB length is 16 bytes */
1112                 if (ccb->csio.cdb_len >
1113                     sizeof (((PTR_MSG_SCSI_IO_REQUEST)0)->CDB)) {
1114                         ccb->ccb_h.status = CAM_REQ_INVALID;
1115                         xpt_done(ccb);
1116                         return;
1117                 }
1118                 ccb->csio.scsi_status = SCSI_STATUS_OK;
1119                 mpt_start(ccb);
1120                 break;
1121
1122         case XPT_ABORT:
1123                 /*
1124                  * XXX: Need to implement
1125                  */
1126                 ccb->ccb_h.status = CAM_UA_ABORT;
1127                 xpt_done(ccb);
1128                 break;
1129
1130 #ifdef  CAM_NEW_TRAN_CODE
1131 #define IS_CURRENT_SETTINGS(c)  (c->type == CTS_TYPE_CURRENT_SETTINGS)
1132 #else
1133 #define IS_CURRENT_SETTINGS(c)  (c->flags & CCB_TRANS_CURRENT_SETTINGS)
1134 #endif
1135 #define DP_DISC_ENABLE  0x1
1136 #define DP_DISC_DISABL  0x2
1137 #define DP_DISC         (DP_DISC_ENABLE|DP_DISC_DISABL)
1138
1139 #define DP_TQING_ENABLE 0x4
1140 #define DP_TQING_DISABL 0x8
1141 #define DP_TQING        (DP_TQING_ENABLE|DP_TQING_DISABL)
1142
1143 #define DP_WIDE         0x10
1144 #define DP_NARROW       0x20
1145 #define DP_WIDTH        (DP_WIDE|DP_NARROW)
1146
1147 #define DP_SYNC         0x40
1148
1149         case XPT_SET_TRAN_SETTINGS:     /* Nexus Settings */
1150                 cts = &ccb->cts;
1151                 if (!IS_CURRENT_SETTINGS(cts)) {
1152                         ccb->ccb_h.status = CAM_REQ_INVALID;
1153                         xpt_done(ccb);
1154                         break;
1155                 }
1156                 tgt = cts->ccb_h.target_id;
1157                 if (mpt->is_fc == 0) {
1158                         u_int8_t dval = 0;
1159                         u_int period = 0, offset = 0;
1160 #ifndef CAM_NEW_TRAN_CODE
1161                         if (cts->valid & CCB_TRANS_DISC_VALID) {
1162                                 dval |= DP_DISC_ENABLE;
1163                         }
1164                         if (cts->valid & CCB_TRANS_TQ_VALID) {
1165                                 dval |= DP_TQING_ENABLE;
1166                         }
1167                         if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) {
1168                                 if (cts->bus_width)
1169                                         dval |= DP_WIDE;
1170                                 else
1171                                         dval |= DP_NARROW;
1172                         }
1173                         /*
1174                          * Any SYNC RATE of nonzero and SYNC_OFFSET
1175                          * of nonzero will cause us to go to the
1176                          * selected (from NVRAM) maximum value for
1177                          * this device. At a later point, we'll
1178                          * allow finer control.
1179                          */
1180                         if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) &&
1181                             (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID)) {
1182                                 dval |= DP_SYNC;
1183                                 period = cts->sync_period;
1184                                 offset = cts->sync_offset;
1185                         }
1186 #else
1187                         struct ccb_trans_settings_scsi *scsi =
1188                             &cts->proto_specific.scsi;
1189                         struct ccb_trans_settings_spi *spi =
1190                             &cts->xport_specific.spi;
1191
1192                         if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
1193                                 if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
1194                                         dval |= DP_DISC_ENABLE;
1195                                 else
1196                                         dval |= DP_DISC_DISABL;
1197                         }
1198
1199                         if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
1200                                 if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
1201                                         dval |= DP_TQING_ENABLE;
1202                                 else
1203                                         dval |= DP_TQING_DISABL;
1204                         }
1205
1206                         if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
1207                                 if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
1208                                         dval |= DP_WIDE;
1209                                 else
1210                                         dval |= DP_NARROW;
1211                         }
1212
1213                         if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) &&
1214                             (spi->valid & CTS_SPI_VALID_SYNC_RATE) &&
1215                             (spi->sync_period && spi->sync_offset)) {
1216                                 dval |= DP_SYNC;
1217                                 period = spi->sync_period;
1218                                 offset = spi->sync_offset;
1219                         }
1220 #endif
1221                         CAMLOCK_2_MPTLOCK(mpt);
1222                         if (dval & DP_DISC_ENABLE) {
1223                                 mpt->mpt_disc_enable |= (1 << tgt);
1224                         } else if (dval & DP_DISC_DISABL) {
1225                                 mpt->mpt_disc_enable &= ~(1 << tgt);
1226                         }
1227                         if (dval & DP_TQING_ENABLE) {
1228                                 mpt->mpt_tag_enable |= (1 << tgt);
1229                         } else if (dval & DP_TQING_DISABL) {
1230                                 mpt->mpt_tag_enable &= ~(1 << tgt);
1231                         }
1232                         if (dval & DP_WIDTH) {
1233                                 if (mpt_setwidth(mpt, tgt, dval & DP_WIDE)) {
1234                                         ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1235                                         MPTLOCK_2_CAMLOCK(mpt);
1236                                         xpt_done(ccb);
1237                                         break;
1238                                 }
1239                         }
1240                         if (dval & DP_SYNC) {
1241                                 if (mpt_setsync(mpt, tgt, period, offset)) {
1242                                         ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1243                                         MPTLOCK_2_CAMLOCK(mpt);
1244                                         xpt_done(ccb);
1245                                         break;
1246                                 }
1247                         }
1248                         MPTLOCK_2_CAMLOCK(mpt);
1249                         if (mpt->verbose > 1) {
1250                                 device_printf(mpt->dev, 
1251                                     "SET tgt %d flags %x period %x off %x\n",
1252                                     tgt, dval, period, offset);
1253                         }
1254                 }
1255                 ccb->ccb_h.status = CAM_REQ_CMP;
1256                 xpt_done(ccb);
1257                 break;
1258
1259         case XPT_GET_TRAN_SETTINGS:
1260                 cts = &ccb->cts;
1261                 tgt = cts->ccb_h.target_id;
1262                 if (mpt->is_fc) {
1263 #ifndef CAM_NEW_TRAN_CODE
1264                         /*
1265                          * a lot of normal SCSI things don't make sense.
1266                          */
1267                         cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
1268                         cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
1269                         /*
1270                          * How do you measure the width of a high
1271                          * speed serial bus? Well, in bytes.
1272                          *
1273                          * Offset and period make no sense, though, so we set
1274                          * (above) a 'base' transfer speed to be gigabit.
1275                          */
1276                         cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1277 #else
1278                         struct ccb_trans_settings_fc *fc =
1279                             &cts->xport_specific.fc;
1280
1281                         cts->protocol = PROTO_SCSI;
1282                         cts->protocol_version = SCSI_REV_2;
1283                         cts->transport = XPORT_FC;
1284                         cts->transport_version = 0;
1285
1286                         fc->valid = CTS_FC_VALID_SPEED;
1287                         fc->bitrate = 100000;   /* XXX: Need for 2Gb/s */
1288                         /* XXX: need a port database for each target */
1289 #endif
1290                 } else {
1291 #ifdef  CAM_NEW_TRAN_CODE
1292                         struct ccb_trans_settings_scsi *scsi =
1293                             &cts->proto_specific.scsi;
1294                         struct ccb_trans_settings_spi *spi =
1295                             &cts->xport_specific.spi;
1296 #endif
1297                         u_int8_t dval, pval, oval;
1298
1299                         /*
1300                          * We aren't going off of Port PAGE2 params for
1301                          * tagged queuing or disconnect capabilities
1302                          * for current settings. For goal settings,
1303                          * we assert all capabilities- we've had some
1304                          * problems with reading NVRAM data.
1305                          */
1306                         if (IS_CURRENT_SETTINGS(cts)) {
1307                                 fCONFIG_PAGE_SCSI_DEVICE_0 tmp;
1308                                 dval = 0;
1309
1310                                 tmp = mpt->mpt_dev_page0[tgt];
1311                                 CAMLOCK_2_MPTLOCK(mpt);
1312                                 if (mpt_read_cfg_page(mpt, tgt, &tmp.Header)) {
1313                                         device_printf(mpt->dev,
1314                                             "cannot get target %d DP0\n", tgt);
1315                                 } else  {
1316                                         if (mpt->verbose > 1) {
1317                                                 device_printf(mpt->dev,
1318                             "SPI Tgt %d Page 0: NParms %x Information %x\n",
1319                                                     tgt,
1320                                                     tmp.NegotiatedParameters,
1321                                                     tmp.Information);
1322                                         }
1323                                 }
1324                                 MPTLOCK_2_CAMLOCK(mpt);
1325
1326                                 if (tmp.NegotiatedParameters & 
1327                                     MPI_SCSIDEVPAGE0_NP_WIDE)
1328                                         dval |= DP_WIDE;
1329
1330                                 if (mpt->mpt_disc_enable & (1 << tgt)) {
1331                                         dval |= DP_DISC_ENABLE;
1332                                 }
1333                                 if (mpt->mpt_tag_enable & (1 << tgt)) {
1334                                         dval |= DP_TQING_ENABLE;
1335                                 }
1336                                 oval = (tmp.NegotiatedParameters >> 16) & 0xff;
1337                                 pval = (tmp.NegotiatedParameters >>  8) & 0xff;
1338                         } else {
1339                                 /*
1340                                  * XXX: Fix wrt NVRAM someday. Attempts
1341                                  * XXX: to read port page2 device data
1342                                  * XXX: just returns zero in these areas.
1343                                  */
1344                                 dval = DP_WIDE|DP_DISC|DP_TQING;
1345                                 oval = (mpt->mpt_port_page0.Capabilities >> 16);
1346                                 pval = (mpt->mpt_port_page0.Capabilities >>  8);
1347                         }
1348 #ifndef CAM_NEW_TRAN_CODE
1349                         cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
1350                         if (dval & DP_DISC_ENABLE) {
1351                                 cts->flags |= CCB_TRANS_DISC_ENB;
1352                         }
1353                         if (dval & DP_TQING_ENABLE) {
1354                                 cts->flags |= CCB_TRANS_TAG_ENB;
1355                         }
1356                         if (dval & DP_WIDE) {
1357                                 cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
1358                         } else {
1359                                 cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1360                         }
1361                         cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
1362                             CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
1363                         if (oval) {
1364                                 cts->sync_period = pval;
1365                                 cts->sync_offset = oval;
1366                                 cts->valid |=
1367                                     CCB_TRANS_SYNC_RATE_VALID |
1368                                     CCB_TRANS_SYNC_OFFSET_VALID;
1369                         }
1370 #else
1371                         cts->protocol = PROTO_SCSI;
1372                         cts->protocol_version = SCSI_REV_2;
1373                         cts->transport = XPORT_SPI;
1374                         cts->transport_version = 2;
1375
1376                         scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1377                         spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
1378                         if (dval & DP_DISC_ENABLE) {
1379                                 spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
1380                         }
1381                         if (dval & DP_TQING_ENABLE) {
1382                                 scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
1383                         }
1384                         if (oval && pval) {
1385                                 spi->sync_offset = oval;
1386                                 spi->sync_period = pval;
1387                                 spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
1388                                 spi->valid |= CTS_SPI_VALID_SYNC_RATE;
1389                         }
1390                         spi->valid |= CTS_SPI_VALID_BUS_WIDTH;
1391                         if (dval & DP_WIDE) {
1392                                 spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
1393                         } else {
1394                                 spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1395                         }
1396                         if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
1397                                 scsi->valid = CTS_SCSI_VALID_TQ;
1398                                 spi->valid |= CTS_SPI_VALID_DISC;
1399                         } else {
1400                                 scsi->valid = 0;
1401                         }
1402 #endif
1403                         if (mpt->verbose > 1) {
1404                                 device_printf(mpt->dev, 
1405                                     "GET %s tgt %d flags %x period %x off %x\n",
1406                                     IS_CURRENT_SETTINGS(cts)? "ACTIVE" :
1407                                     "NVRAM", tgt, dval, pval, oval);
1408                         }
1409                 }
1410                 ccb->ccb_h.status = CAM_REQ_CMP;
1411                 xpt_done(ccb);
1412                 break;
1413
1414         case XPT_CALC_GEOMETRY:
1415         {
1416                 struct ccb_calc_geometry *ccg;
1417                 u_int32_t secs_per_cylinder;
1418                 u_int32_t size_mb;
1419
1420                 ccg = &ccb->ccg;
1421                 if (ccg->block_size == 0) {
1422                         ccb->ccb_h.status = CAM_REQ_INVALID;
1423                         xpt_done(ccb);
1424                         break;
1425                 }
1426
1427                 size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size);
1428                 if (size_mb > 1024) {
1429                         ccg->heads = 255;
1430                         ccg->secs_per_track = 63;
1431                 } else {
1432                         ccg->heads = 64;
1433                         ccg->secs_per_track = 32;
1434                 }
1435                 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
1436                 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
1437                 ccb->ccb_h.status = CAM_REQ_CMP;
1438                 xpt_done(ccb);
1439                 break;
1440         }
1441         case XPT_PATH_INQ:              /* Path routing inquiry */
1442         {
1443                 struct ccb_pathinq *cpi = &ccb->cpi;
1444
1445                 cpi->version_num = 1;
1446                 cpi->target_sprt = 0;
1447                 cpi->hba_eng_cnt = 0;
1448                 cpi->max_lun = 7;
1449                 cpi->bus_id = cam_sim_bus(sim);
1450                 if (mpt->is_fc) {
1451                         cpi->max_target = 255;
1452                         cpi->hba_misc = PIM_NOBUSRESET;
1453                         cpi->initiator_id = cpi->max_target + 1;
1454                         cpi->base_transfer_speed = 100000;
1455                         cpi->hba_inquiry = PI_TAG_ABLE;
1456                 } else {
1457                         cpi->initiator_id = mpt->mpt_ini_id;
1458                         cpi->base_transfer_speed = 3300;
1459                         cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
1460                         cpi->hba_misc = 0;
1461                         cpi->max_target = 15;
1462                 }
1463
1464                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1465                 strncpy(cpi->hba_vid, "LSI", HBA_IDLEN);
1466                 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1467                 cpi->unit_number = cam_sim_unit(sim);
1468                 cpi->ccb_h.status = CAM_REQ_CMP;
1469                 xpt_done(ccb);
1470                 break;
1471         }
1472         default:
1473                 ccb->ccb_h.status = CAM_REQ_INVALID;
1474                 xpt_done(ccb);
1475                 break;
1476         }
1477 }
1478
1479 static int
1480 mpt_setwidth(mpt_softc_t *mpt, int tgt, int onoff)
1481 {
1482         fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
1483         tmp = mpt->mpt_dev_page1[tgt];
1484         if (onoff) {
1485                 tmp.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE;
1486         } else {
1487                 tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE;
1488         }
1489         if (mpt_write_cfg_page(mpt, tgt, &tmp.Header)) {
1490                 return (-1);
1491         }
1492         if (mpt_read_cfg_page(mpt, tgt, &tmp.Header)) {
1493                 return (-1);
1494         }
1495         mpt->mpt_dev_page1[tgt] = tmp;
1496         if (mpt->verbose > 1) {
1497                 device_printf(mpt->dev,
1498                     "SPI Target %d Page 1: RequestedParameters %x Config %x\n",
1499                     tgt, mpt->mpt_dev_page1[tgt].RequestedParameters,
1500                     mpt->mpt_dev_page1[tgt].Configuration);
1501         }
1502         return (0);
1503 }
1504
1505 static int
1506 mpt_setsync(mpt_softc_t *mpt, int tgt, int period, int offset)
1507 {
1508         fCONFIG_PAGE_SCSI_DEVICE_1 tmp;
1509         tmp = mpt->mpt_dev_page1[tgt];
1510         tmp.RequestedParameters &=
1511             ~MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK;
1512         tmp.RequestedParameters &=
1513             ~MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK;
1514         tmp.RequestedParameters &=
1515             ~MPI_SCSIDEVPAGE1_RP_DT;
1516         tmp.RequestedParameters &=
1517             ~MPI_SCSIDEVPAGE1_RP_QAS;
1518         tmp.RequestedParameters &=
1519             ~MPI_SCSIDEVPAGE1_RP_IU;
1520         /*
1521          * XXX: For now, we're ignoring specific settings
1522          */
1523         if (period && offset) {
1524                 int factor, offset, np;
1525                 factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff;
1526                 offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff;
1527                 np = 0;
1528                 if (factor < 0x9) {
1529                         np |= MPI_SCSIDEVPAGE1_RP_QAS;
1530                         np |= MPI_SCSIDEVPAGE1_RP_IU;
1531                 }
1532                 if (factor < 0xa) {
1533                         np |= MPI_SCSIDEVPAGE1_RP_DT;
1534                 }
1535                 np |= (factor << 8) | (offset << 16);
1536                 tmp.RequestedParameters |= np;
1537         }
1538         if (mpt_write_cfg_page(mpt, tgt, &tmp.Header)) {
1539                 return (-1);
1540         }
1541         if (mpt_read_cfg_page(mpt, tgt, &tmp.Header)) {
1542                 return (-1);
1543         }
1544         mpt->mpt_dev_page1[tgt] = tmp;
1545         if (mpt->verbose > 1) {
1546                 device_printf(mpt->dev,
1547                     "SPI Target %d Page 1: RParams %x Config %x\n",
1548                     tgt, mpt->mpt_dev_page1[tgt].RequestedParameters,
1549                     mpt->mpt_dev_page1[tgt].Configuration);
1550         }
1551         return (0);
1552 }