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