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