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