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