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