]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/tws/tws.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / tws / tws.c
1 /*
2  * Copyright (c) 2010, LSI Corp.
3  * All rights reserved.
4  * Author : Manjunath Ranganathaiah
5  * Support: freebsdraid@lsi.com
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of the <ORGANIZATION> nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <dev/tws/tws.h>
39 #include <dev/tws/tws_services.h>
40 #include <dev/tws/tws_hdm.h>
41
42 #include <cam/cam.h>
43 #include <cam/cam_ccb.h>
44
45 MALLOC_DEFINE(M_TWS, "twsbuf", "buffers used by tws driver");
46 int tws_queue_depth = TWS_MAX_REQS;
47 int tws_enable_msi = 0;
48 int tws_enable_msix = 0;
49
50
51
52 /* externs */
53 extern int tws_cam_attach(struct tws_softc *sc);
54 extern void tws_cam_detach(struct tws_softc *sc);
55 extern int tws_init_ctlr(struct tws_softc *sc);
56 extern boolean tws_ctlr_ready(struct tws_softc *sc);
57 extern void tws_turn_off_interrupts(struct tws_softc *sc);
58 extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
59                                 u_int8_t q_type );
60 extern struct tws_request *tws_q_remove_request(struct tws_softc *sc,
61                                    struct tws_request *req, u_int8_t q_type );
62 extern struct tws_request *tws_q_remove_head(struct tws_softc *sc, 
63                                                        u_int8_t q_type );
64 extern boolean tws_get_response(struct tws_softc *sc, u_int16_t *req_id);
65 extern boolean tws_ctlr_reset(struct tws_softc *sc);
66 extern void tws_intr(void *arg);
67 extern int tws_use_32bit_sgls;
68
69
70 struct tws_request *tws_get_request(struct tws_softc *sc, u_int16_t type);
71 int tws_init_connect(struct tws_softc *sc, u_int16_t mc);
72 void tws_send_event(struct tws_softc *sc, u_int8_t event);
73 uint8_t tws_get_state(struct tws_softc *sc);
74 void tws_release_request(struct tws_request *req);
75
76
77
78 /* Function prototypes */
79 static d_open_t     tws_open;
80 static d_close_t    tws_close;
81 static d_read_t     tws_read;
82 static d_write_t    tws_write;
83 extern d_ioctl_t    tws_ioctl;
84
85 static int tws_init(struct tws_softc *sc);
86 static void tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs,
87                            int nseg, int error);
88
89 static int tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size);
90 static int tws_init_aen_q(struct tws_softc *sc);
91 static int tws_init_trace_q(struct tws_softc *sc);
92 static int tws_setup_irq(struct tws_softc *sc);
93 int tws_setup_intr(struct tws_softc *sc, int irqs);
94 int tws_teardown_intr(struct tws_softc *sc);
95
96
97 /* Character device entry points */
98
99 static struct cdevsw tws_cdevsw = {
100     .d_version =    D_VERSION,
101     .d_open =   tws_open,
102     .d_close =  tws_close,
103     .d_read =   tws_read,
104     .d_write =  tws_write,
105     .d_ioctl =  tws_ioctl,
106     .d_name =   "tws",
107 };
108
109 /*
110  * In the cdevsw routines, we find our softc by using the si_drv1 member
111  * of struct cdev.  We set this variable to point to our softc in our
112  * attach routine when we create the /dev entry.
113  */
114
115 int
116 tws_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td)
117 {
118     struct tws_softc *sc = dev->si_drv1;
119
120     if ( sc ) 
121         TWS_TRACE_DEBUG(sc, "entry", dev, oflags);
122     return (0);
123 }
124
125 int
126 tws_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td)
127 {
128     struct tws_softc *sc = dev->si_drv1;
129
130     if ( sc )
131         TWS_TRACE_DEBUG(sc, "entry", dev, fflag);
132     return (0);
133 }
134
135 int
136 tws_read(struct cdev *dev, struct uio *uio, int ioflag)
137 {
138     struct tws_softc *sc = dev->si_drv1;
139
140     if ( sc )
141         TWS_TRACE_DEBUG(sc, "entry", dev, ioflag);
142     return (0);
143 }
144
145 int
146 tws_write(struct cdev *dev, struct uio *uio, int ioflag)
147 {
148     struct tws_softc *sc = dev->si_drv1;
149
150     if ( sc ) 
151         TWS_TRACE_DEBUG(sc, "entry", dev, ioflag);
152     return (0);
153 }
154
155 /* PCI Support Functions */
156
157 /*
158  * Compare the device ID of this device against the IDs that this driver
159  * supports.  If there is a match, set the description and return success.
160  */
161 static int
162 tws_probe(device_t dev)
163 {
164     static u_int8_t first_ctlr = 1;
165
166     if ((pci_get_vendor(dev) == TWS_VENDOR_ID) &&
167         (pci_get_device(dev) == TWS_DEVICE_ID)) {
168         device_set_desc(dev, "LSI 3ware SAS/SATA Storage Controller");
169         if (first_ctlr) {
170             printf("LSI 3ware device driver for SAS/SATA storage "
171                     "controllers, version: %s\n", TWS_DRIVER_VERSION_STRING);
172             first_ctlr = 0;
173         }
174
175         return(BUS_PROBE_DEFAULT);
176     }
177     return (ENXIO);
178 }
179
180 /* Attach function is only called if the probe is successful. */
181
182 static int
183 tws_attach(device_t dev)
184 {
185     struct tws_softc *sc = device_get_softc(dev);
186     u_int32_t bar;
187     int error=0,i;
188
189     /* no tracing yet */
190     /* Look up our softc and initialize its fields. */
191     sc->tws_dev = dev;
192     sc->device_id = pci_get_device(dev);
193     sc->subvendor_id = pci_get_subvendor(dev);
194     sc->subdevice_id = pci_get_subdevice(dev);
195
196     /* Intialize mutexes */
197     mtx_init( &sc->q_lock, "tws_q_lock", NULL, MTX_DEF);
198     mtx_init( &sc->sim_lock,  "tws_sim_lock", NULL, MTX_DEF);
199     mtx_init( &sc->gen_lock,  "tws_gen_lock", NULL, MTX_DEF);
200     mtx_init( &sc->io_lock,  "tws_io_lock", NULL, MTX_DEF | MTX_RECURSE);
201     callout_init(&sc->stats_timer, CALLOUT_MPSAFE);
202
203     if ( tws_init_trace_q(sc) == FAILURE )
204         printf("trace init failure\n");
205     /* send init event */
206     mtx_lock(&sc->gen_lock);
207     tws_send_event(sc, TWS_INIT_START);
208     mtx_unlock(&sc->gen_lock);
209
210
211 #if _BYTE_ORDER == _BIG_ENDIAN
212     TWS_TRACE(sc, "BIG endian", 0, 0);
213 #endif
214     /* sysctl context setup */
215     sysctl_ctx_init(&sc->tws_clist);
216     sc->tws_oidp = SYSCTL_ADD_NODE(&sc->tws_clist,
217                                    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
218                                    device_get_nameunit(dev), 
219                                    CTLFLAG_RD, 0, "");
220     if ( sc->tws_oidp == NULL ) {
221         tws_log(sc, SYSCTL_TREE_NODE_ADD);
222         goto attach_fail_1;
223     }
224     SYSCTL_ADD_STRING(&sc->tws_clist, SYSCTL_CHILDREN(sc->tws_oidp),
225                       OID_AUTO, "driver_version", CTLFLAG_RD,
226                       TWS_DRIVER_VERSION_STRING, 0, "TWS driver version");
227
228     pci_enable_busmaster(dev);
229
230     bar = pci_read_config(dev, TWS_PCI_BAR0, 4);
231     TWS_TRACE_DEBUG(sc, "bar0 ", bar, 0);
232     bar = pci_read_config(dev, TWS_PCI_BAR1, 4);
233     bar = bar & ~TWS_BIT2;
234     TWS_TRACE_DEBUG(sc, "bar1 ", bar, 0);
235  
236     /* MFA base address is BAR2 register used for 
237      * push mode. Firmware will evatualy move to 
238      * pull mode during witch this needs to change
239      */ 
240 #ifndef TWS_PULL_MODE_ENABLE
241     sc->mfa_base = (u_int64_t)pci_read_config(dev, TWS_PCI_BAR2, 4);
242     sc->mfa_base = sc->mfa_base & ~TWS_BIT2;
243     TWS_TRACE_DEBUG(sc, "bar2 ", sc->mfa_base, 0);
244 #endif
245
246     /* allocate MMIO register space */ 
247     sc->reg_res_id = TWS_PCI_BAR1; /* BAR1 offset */
248     if ((sc->reg_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
249                                 &(sc->reg_res_id), 0, ~0, 1, RF_ACTIVE))
250                                 == NULL) {
251         tws_log(sc, ALLOC_MEMORY_RES);
252         goto attach_fail_1;
253     }
254     sc->bus_tag = rman_get_bustag(sc->reg_res);
255     sc->bus_handle = rman_get_bushandle(sc->reg_res);
256
257 #ifndef TWS_PULL_MODE_ENABLE
258     /* Allocate bus space for inbound mfa */ 
259     sc->mfa_res_id = TWS_PCI_BAR2; /* BAR2 offset */
260     if ((sc->mfa_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
261                           &(sc->mfa_res_id), 0, ~0, 0x100000, RF_ACTIVE))
262                                 == NULL) {
263         tws_log(sc, ALLOC_MEMORY_RES);
264         goto attach_fail_2;
265     }
266     sc->bus_mfa_tag = rman_get_bustag(sc->mfa_res);
267     sc->bus_mfa_handle = rman_get_bushandle(sc->mfa_res);
268 #endif
269
270     /* Allocate and register our interrupt. */
271     sc->intr_type = TWS_INTx; /* default */
272
273     if ( tws_enable_msi )
274         sc->intr_type = TWS_MSI;
275     if ( tws_setup_irq(sc) == FAILURE ) {
276         tws_log(sc, ALLOC_MEMORY_RES);
277         goto attach_fail_3;
278     }
279
280     /*
281      * Create a /dev entry for this device.  The kernel will assign us
282      * a major number automatically.  We use the unit number of this
283      * device as the minor number and name the character device
284      * "tws<unit>".
285      */
286     sc->tws_cdev = make_dev(&tws_cdevsw, device_get_unit(dev),
287         UID_ROOT, GID_OPERATOR, S_IRUSR | S_IWUSR, "tws%u", 
288         device_get_unit(dev));
289     sc->tws_cdev->si_drv1 = sc;
290
291     if ( tws_init(sc) == FAILURE ) {
292         tws_log(sc, TWS_INIT_FAILURE);
293         goto attach_fail_4;
294     }
295     if ( tws_init_ctlr(sc) == FAILURE ) {
296         tws_log(sc, TWS_CTLR_INIT_FAILURE);
297         goto attach_fail_4;
298     }
299     if ((error = tws_cam_attach(sc))) {
300         tws_log(sc, TWS_CAM_ATTACH);
301         goto attach_fail_4;
302     }
303     /* send init complete event */
304     mtx_lock(&sc->gen_lock);
305     tws_send_event(sc, TWS_INIT_COMPLETE);
306     mtx_unlock(&sc->gen_lock);
307         
308     TWS_TRACE_DEBUG(sc, "attached successfully", 0, sc->device_id);
309     return(0);
310
311 attach_fail_4:
312     tws_teardown_intr(sc);
313     destroy_dev(sc->tws_cdev);
314 attach_fail_3:
315     for(i=0;i<sc->irqs;i++) {
316         if ( sc->irq_res[i] ){
317             if (bus_release_resource(sc->tws_dev,
318                  SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i]))
319                 TWS_TRACE(sc, "bus irq res", 0, 0);
320         }
321     }
322 #ifndef TWS_PULL_MODE_ENABLE
323 attach_fail_2: 
324 #endif
325     if ( sc->mfa_res ){
326         if (bus_release_resource(sc->tws_dev,
327                  SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res))
328             TWS_TRACE(sc, "bus release ", 0, sc->mfa_res_id);
329     }
330     if ( sc->reg_res ){
331         if (bus_release_resource(sc->tws_dev,
332                  SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res))
333             TWS_TRACE(sc, "bus release2 ", 0, sc->reg_res_id);
334     }
335 attach_fail_1:
336     mtx_destroy(&sc->q_lock);
337     mtx_destroy(&sc->sim_lock);
338     mtx_destroy(&sc->gen_lock);
339     mtx_destroy(&sc->io_lock);
340     sysctl_ctx_free(&sc->tws_clist);
341     return (ENXIO);
342 }
343
344 /* Detach device. */
345
346 static int
347 tws_detach(device_t dev)
348 {
349     struct tws_softc *sc = device_get_softc(dev);
350     int i;
351     u_int32_t reg;
352
353     TWS_TRACE_DEBUG(sc, "entry", 0, 0);
354
355     mtx_lock(&sc->gen_lock);
356     tws_send_event(sc, TWS_UNINIT_START);
357     mtx_unlock(&sc->gen_lock);
358
359     /* needs to disable interrupt before detaching from cam */
360     tws_turn_off_interrupts(sc);
361     /* clear door bell */
362     tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4);
363     reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4);
364     TWS_TRACE_DEBUG(sc, "turn-off-intr", reg, 0);
365     sc->obfl_q_overrun = false;
366     tws_init_connect(sc, 1);
367
368     /* Teardown the state in our softc created in our attach routine. */
369     /* Disconnect the interrupt handler. */
370     tws_teardown_intr(sc);
371
372     /* Release irq resource */
373     for(i=0;i<sc->irqs;i++) {
374         if ( sc->irq_res[i] ){
375             if (bus_release_resource(sc->tws_dev,
376                      SYS_RES_IRQ, sc->irq_res_id[i], sc->irq_res[i]))
377                 TWS_TRACE(sc, "bus release irq resource", 
378                                        i, sc->irq_res_id[i]);
379         }
380     }
381     if ( sc->intr_type == TWS_MSI ) {
382         pci_release_msi(sc->tws_dev);
383     }
384
385     tws_cam_detach(sc);
386
387     /* Release memory resource */
388     if ( sc->mfa_res ){
389         if (bus_release_resource(sc->tws_dev,
390                  SYS_RES_MEMORY, sc->mfa_res_id, sc->mfa_res))
391             TWS_TRACE(sc, "bus release mem resource", 0, sc->mfa_res_id);
392     }
393     if ( sc->reg_res ){
394         if (bus_release_resource(sc->tws_dev,
395                  SYS_RES_MEMORY, sc->reg_res_id, sc->reg_res))
396             TWS_TRACE(sc, "bus release mem resource", 0, sc->reg_res_id);
397     }
398
399     for ( i=0; i< tws_queue_depth; i++) {
400             if (sc->reqs[i].dma_map)
401                     bus_dmamap_destroy(sc->data_tag, sc->reqs[i].dma_map);
402             callout_drain(&sc->reqs[i].timeout);
403     }
404
405     callout_drain(&sc->stats_timer);
406     free(sc->reqs, M_TWS);
407     free(sc->sense_bufs, M_TWS);
408     free(sc->scan_ccb, M_TWS);
409     if (sc->ioctl_data_mem)
410             bus_dmamem_free(sc->data_tag, sc->ioctl_data_mem, sc->ioctl_data_map);
411     if (sc->data_tag)
412             bus_dma_tag_destroy(sc->data_tag);
413     free(sc->aen_q.q, M_TWS);
414     free(sc->trace_q.q, M_TWS);
415     mtx_destroy(&sc->q_lock);
416     mtx_destroy(&sc->sim_lock);
417     mtx_destroy(&sc->gen_lock);
418     mtx_destroy(&sc->io_lock);
419     destroy_dev(sc->tws_cdev);
420     sysctl_ctx_free(&sc->tws_clist);
421     return (0);
422 }
423
424 int
425 tws_setup_intr(struct tws_softc *sc, int irqs)
426 {
427     int i, error;
428
429     for(i=0;i<irqs;i++) {
430         if (!(sc->intr_handle[i])) {
431             if ((error = bus_setup_intr(sc->tws_dev, sc->irq_res[i],
432                                     INTR_TYPE_CAM | INTR_MPSAFE,
433 #if (__FreeBSD_version >= 700000)
434                                     NULL, 
435 #endif
436                                     tws_intr, sc, &sc->intr_handle[i]))) {
437                 tws_log(sc, SETUP_INTR_RES);
438                 return(FAILURE);
439             }
440         }
441     }
442     return(SUCCESS);
443
444 }
445
446
447 int
448 tws_teardown_intr(struct tws_softc *sc)
449 {
450     int i, error;
451
452     for(i=0;i<sc->irqs;i++) {
453         if (sc->intr_handle[i]) {
454             error = bus_teardown_intr(sc->tws_dev,
455                                       sc->irq_res[i], sc->intr_handle[i]);
456             sc->intr_handle[i] = NULL;
457         }
458     }
459     return(SUCCESS);
460 }
461
462
463 static int 
464 tws_setup_irq(struct tws_softc *sc)
465 {
466     int messages;
467
468     switch(sc->intr_type) {
469         case TWS_INTx :
470             sc->irqs = 1;
471             sc->irq_res_id[0] = 0;
472             sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ,
473                             &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE);
474             if ( ! sc->irq_res[0] )
475                 return(FAILURE);
476             if ( tws_setup_intr(sc, sc->irqs) == FAILURE )
477                 return(FAILURE);
478             device_printf(sc->tws_dev, "Using legacy INTx\n");
479             break;
480         case TWS_MSI :
481             sc->irqs = 1;
482             sc->irq_res_id[0] = 1;
483             messages = 1;
484             if (pci_alloc_msi(sc->tws_dev, &messages) != 0 ) {
485                 TWS_TRACE(sc, "pci alloc msi fail", 0, messages);
486                 return(FAILURE);
487             }
488             sc->irq_res[0] = bus_alloc_resource_any(sc->tws_dev, SYS_RES_IRQ,
489                               &sc->irq_res_id[0], RF_SHAREABLE | RF_ACTIVE);
490               
491             if ( !sc->irq_res[0]  )
492                 return(FAILURE);
493             if ( tws_setup_intr(sc, sc->irqs) == FAILURE )
494                 return(FAILURE);
495             device_printf(sc->tws_dev, "Using MSI\n");
496             break;
497
498     }
499
500     return(SUCCESS);
501 }
502
503 static int
504 tws_init(struct tws_softc *sc)
505 {
506
507     u_int32_t max_sg_elements;
508     u_int32_t dma_mem_size;
509     int error;
510     u_int32_t reg;
511
512     sc->seq_id = 0;
513     if ( tws_queue_depth > TWS_MAX_REQS )
514         tws_queue_depth = TWS_MAX_REQS;
515     if (tws_queue_depth < TWS_RESERVED_REQS+1)
516         tws_queue_depth = TWS_RESERVED_REQS+1;
517     sc->is64bit = (sizeof(bus_addr_t) == 8) ? true : false;
518     max_sg_elements = (sc->is64bit && !tws_use_32bit_sgls) ? 
519                                  TWS_MAX_64BIT_SG_ELEMENTS : 
520                                  TWS_MAX_32BIT_SG_ELEMENTS;
521     dma_mem_size = (sizeof(struct tws_command_packet) * tws_queue_depth) +
522                              (TWS_SECTOR_SIZE) ;
523     if ( bus_dma_tag_create(bus_get_dma_tag(sc->tws_dev), /* PCI parent */ 
524                             TWS_ALIGNMENT,           /* alignment */
525                             0,                       /* boundary */
526                             BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
527                             BUS_SPACE_MAXADDR,       /* highaddr */
528                             NULL, NULL,              /* filter, filterarg */
529                             BUS_SPACE_MAXSIZE,       /* maxsize */
530                             max_sg_elements,         /* numsegs */
531                             BUS_SPACE_MAXSIZE,       /* maxsegsize */
532                             0,                       /* flags */
533                             NULL, NULL,              /* lockfunc, lockfuncarg */
534                             &sc->parent_tag          /* tag */
535                            )) {
536         TWS_TRACE_DEBUG(sc, "DMA parent tag Create fail", max_sg_elements, 
537                                                     sc->is64bit);
538         return(ENOMEM);
539     }
540     /* In bound message frame requires 16byte alignment.
541      * Outbound MF's can live with 4byte alignment - for now just 
542      * use 16 for both.
543      */
544     if ( bus_dma_tag_create(sc->parent_tag,       /* parent */          
545                             TWS_IN_MF_ALIGNMENT,  /* alignment */
546                             0,                    /* boundary */
547                             BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
548                             BUS_SPACE_MAXADDR,    /* highaddr */
549                             NULL, NULL,           /* filter, filterarg */
550                             dma_mem_size,         /* maxsize */
551                             1,                    /* numsegs */
552                             BUS_SPACE_MAXSIZE,    /* maxsegsize */
553                             0,                    /* flags */
554                             NULL, NULL,           /* lockfunc, lockfuncarg */
555                             &sc->cmd_tag          /* tag */
556                            )) {
557         TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit);
558         return(ENOMEM);
559     }
560
561     if (bus_dmamem_alloc(sc->cmd_tag, &sc->dma_mem,
562                     BUS_DMA_NOWAIT, &sc->cmd_map)) {
563         TWS_TRACE_DEBUG(sc, "DMA mem alloc fail", max_sg_elements, sc->is64bit);
564         return(ENOMEM);
565     }
566
567     /* if bus_dmamem_alloc succeeds then bus_dmamap_load will succeed */
568     sc->dma_mem_phys=0;
569     error = bus_dmamap_load(sc->cmd_tag, sc->cmd_map, sc->dma_mem,
570                     dma_mem_size, tws_dmamap_cmds_load_cbfn,
571                     &sc->dma_mem_phys, 0);
572
573    /*
574     * Create a dma tag for data buffers; size will be the maximum
575     * possible I/O size (128kB).
576     */
577     if (bus_dma_tag_create(sc->parent_tag,         /* parent */
578                            TWS_ALIGNMENT,          /* alignment */
579                            0,                      /* boundary */
580                            BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
581                            BUS_SPACE_MAXADDR,      /* highaddr */
582                            NULL, NULL,             /* filter, filterarg */
583                            TWS_MAX_IO_SIZE,        /* maxsize */
584                            max_sg_elements,        /* nsegments */
585                            TWS_MAX_IO_SIZE,        /* maxsegsize */
586                            BUS_DMA_ALLOCNOW,       /* flags */
587                            busdma_lock_mutex,      /* lockfunc */
588                            &sc->io_lock,           /* lockfuncarg */
589                            &sc->data_tag           /* tag */)) {
590         TWS_TRACE_DEBUG(sc, "DMA cmd tag Create fail", max_sg_elements, sc->is64bit);
591         return(ENOMEM);
592     }
593
594     sc->reqs = malloc(sizeof(struct tws_request) * tws_queue_depth, M_TWS,
595                       M_WAITOK | M_ZERO);
596     if ( sc->reqs == NULL ) {
597         TWS_TRACE_DEBUG(sc, "malloc failed", 0, sc->is64bit);
598         return(ENOMEM);
599     }
600     sc->sense_bufs = malloc(sizeof(struct tws_sense) * tws_queue_depth, M_TWS,
601                       M_WAITOK | M_ZERO);
602     if ( sc->sense_bufs == NULL ) {
603         TWS_TRACE_DEBUG(sc, "sense malloc failed", 0, sc->is64bit);
604         return(ENOMEM);
605     }
606     sc->scan_ccb = malloc(sizeof(union ccb), M_TWS, M_WAITOK | M_ZERO);
607     if ( sc->scan_ccb == NULL ) {
608         TWS_TRACE_DEBUG(sc, "ccb malloc failed", 0, sc->is64bit);
609         return(ENOMEM);
610     }
611     if (bus_dmamem_alloc(sc->data_tag, (void **)&sc->ioctl_data_mem,
612             (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &sc->ioctl_data_map)) {
613         device_printf(sc->tws_dev, "Cannot allocate ioctl data mem\n");
614         return(ENOMEM);
615     }
616
617     if ( !tws_ctlr_ready(sc) )
618         if( !tws_ctlr_reset(sc) )
619             return(FAILURE);
620     
621     bzero(&sc->stats, sizeof(struct tws_stats));
622     tws_init_qs(sc);
623     tws_turn_off_interrupts(sc);
624
625     /* 
626      * enable pull mode by setting bit1 .
627      * setting bit0 to 1 will enable interrupt coalesing 
628      * will revisit. 
629      */
630
631 #ifdef TWS_PULL_MODE_ENABLE
632
633     reg = tws_read_reg(sc, TWS_I2O0_CTL, 4);
634     TWS_TRACE_DEBUG(sc, "i20 ctl", reg, TWS_I2O0_CTL);
635     tws_write_reg(sc, TWS_I2O0_CTL, reg | TWS_BIT1, 4);
636
637 #endif
638
639     TWS_TRACE_DEBUG(sc, "dma_mem_phys", sc->dma_mem_phys, TWS_I2O0_CTL);
640     if ( tws_init_reqs(sc, dma_mem_size) == FAILURE )
641         return(FAILURE);
642     if ( tws_init_aen_q(sc) == FAILURE )
643         return(FAILURE);
644
645     return(SUCCESS);
646     
647
648
649 static int
650 tws_init_aen_q(struct tws_softc *sc)
651 {
652     sc->aen_q.head=0;
653     sc->aen_q.tail=0;
654     sc->aen_q.depth=256;
655     sc->aen_q.overflow=0;
656     sc->aen_q.q = malloc(sizeof(struct tws_event_packet)*sc->aen_q.depth, 
657                               M_TWS, M_WAITOK | M_ZERO);
658     if ( ! sc->aen_q.q )
659         return(FAILURE);
660     return(SUCCESS);
661 }
662
663 static int
664 tws_init_trace_q(struct tws_softc *sc)
665 {
666     sc->trace_q.head=0;
667     sc->trace_q.tail=0;
668     sc->trace_q.depth=256;
669     sc->trace_q.overflow=0;
670     sc->trace_q.q = malloc(sizeof(struct tws_trace_rec)*sc->trace_q.depth,
671                               M_TWS, M_WAITOK | M_ZERO);
672     if ( ! sc->trace_q.q )
673         return(FAILURE);
674     return(SUCCESS);
675 }
676
677 static int
678 tws_init_reqs(struct tws_softc *sc, u_int32_t dma_mem_size)
679 {
680
681     struct tws_command_packet *cmd_buf;
682     cmd_buf = (struct tws_command_packet *)sc->dma_mem;
683     int i;
684
685     bzero(cmd_buf, dma_mem_size);
686     TWS_TRACE_DEBUG(sc, "phy cmd", sc->dma_mem_phys, 0);
687     mtx_lock(&sc->q_lock);
688     for ( i=0; i< tws_queue_depth; i++)
689     {
690         if (bus_dmamap_create(sc->data_tag, 0, &sc->reqs[i].dma_map)) {
691             /* log a ENOMEM failure msg here */
692             mtx_unlock(&sc->q_lock);
693             return(FAILURE);
694         } 
695         sc->reqs[i].cmd_pkt =  &cmd_buf[i];
696
697         sc->sense_bufs[i].hdr = &cmd_buf[i].hdr ;
698         sc->sense_bufs[i].hdr_pkt_phy = sc->dma_mem_phys + 
699                               (i * sizeof(struct tws_command_packet));
700
701         sc->reqs[i].cmd_pkt_phy = sc->dma_mem_phys + 
702                               sizeof(struct tws_command_header) +
703                               (i * sizeof(struct tws_command_packet));
704         sc->reqs[i].request_id = i;
705         sc->reqs[i].sc = sc;
706
707         sc->reqs[i].cmd_pkt->hdr.header_desc.size_header = 128;
708
709         callout_init(&sc->reqs[i].timeout, CALLOUT_MPSAFE);
710         sc->reqs[i].state = TWS_REQ_STATE_FREE;
711         if ( i >= TWS_RESERVED_REQS )
712             tws_q_insert_tail(sc, &sc->reqs[i], TWS_FREE_Q);
713     }
714     mtx_unlock(&sc->q_lock);
715     return(SUCCESS);
716 }
717
718 static void
719 tws_dmamap_cmds_load_cbfn(void *arg, bus_dma_segment_t *segs,
720                            int nseg, int error)
721 {
722
723     /* printf("command load done \n"); */
724
725     *((bus_addr_t *)arg) = segs[0].ds_addr;
726 }
727
728 void
729 tws_send_event(struct tws_softc *sc, u_int8_t event)
730 {
731     mtx_assert(&sc->gen_lock, MA_OWNED);
732     TWS_TRACE_DEBUG(sc, "received event ", 0, event);
733     switch (event) {
734
735         case TWS_INIT_START:
736             sc->tws_state = TWS_INIT;
737             break;
738
739         case TWS_INIT_COMPLETE:
740             if (sc->tws_state != TWS_INIT) {
741                 device_printf(sc->tws_dev, "invalid state transition %d => TWS_ONLINE\n", sc->tws_state);
742             } else {
743                 sc->tws_state = TWS_ONLINE;
744             }
745             break;
746
747         case TWS_RESET_START:
748             /* We can transition to reset state from any state except reset*/ 
749             if (sc->tws_state != TWS_RESET) {
750                 sc->tws_prev_state = sc->tws_state;
751                 sc->tws_state = TWS_RESET;
752             }
753             break;
754
755         case TWS_RESET_COMPLETE:
756             if (sc->tws_state != TWS_RESET) {
757                 device_printf(sc->tws_dev, "invalid state transition %d => %d (previous state)\n", sc->tws_state, sc->tws_prev_state);
758             } else {
759                 sc->tws_state = sc->tws_prev_state;
760             }
761             break;
762
763         case TWS_SCAN_FAILURE:
764             if (sc->tws_state != TWS_ONLINE) {
765                 device_printf(sc->tws_dev, "invalid state transition %d => TWS_OFFLINE\n", sc->tws_state);
766             } else {
767                 sc->tws_state = TWS_OFFLINE;
768             }
769             break;
770
771         case TWS_UNINIT_START:
772             if ((sc->tws_state != TWS_ONLINE) && (sc->tws_state != TWS_OFFLINE)) {
773                 device_printf(sc->tws_dev, "invalid state transition %d => TWS_UNINIT\n", sc->tws_state);
774             } else {
775                 sc->tws_state = TWS_UNINIT;
776             }
777             break;
778     }
779
780 }
781
782 uint8_t
783 tws_get_state(struct tws_softc *sc)
784 {
785   
786     return((u_int8_t)sc->tws_state);
787
788 }
789
790 /* Called during system shutdown after sync. */
791
792 static int
793 tws_shutdown(device_t dev)
794 {
795
796     struct tws_softc *sc = device_get_softc(dev);
797
798     TWS_TRACE_DEBUG(sc, "entry", 0, 0);
799
800     tws_turn_off_interrupts(sc);
801     tws_init_connect(sc, 1);
802
803     return (0);
804 }
805
806 /*
807  * Device suspend routine.
808  */
809 static int
810 tws_suspend(device_t dev)
811 {
812     struct tws_softc *sc = device_get_softc(dev);
813
814     if ( sc )
815         TWS_TRACE_DEBUG(sc, "entry", 0, 0);
816     return (0);
817 }
818
819 /*
820  * Device resume routine.
821  */
822 static int
823 tws_resume(device_t dev)
824 {
825
826     struct tws_softc *sc = device_get_softc(dev);
827
828     if ( sc )
829         TWS_TRACE_DEBUG(sc, "entry", 0, 0);
830     return (0);
831 }
832
833
834 struct tws_request *
835 tws_get_request(struct tws_softc *sc, u_int16_t type)
836 {
837     struct mtx *my_mutex = ((type == TWS_REQ_TYPE_SCSI_IO) ? &sc->q_lock : &sc->gen_lock);
838     struct tws_request *r = NULL;
839
840     mtx_lock(my_mutex);
841
842     if (type == TWS_REQ_TYPE_SCSI_IO) {
843         r = tws_q_remove_head(sc, TWS_FREE_Q);
844     } else {
845         if ( sc->reqs[type].state == TWS_REQ_STATE_FREE ) {
846             r = &sc->reqs[type];
847         }
848     }
849
850     if ( r ) {
851         bzero(&r->cmd_pkt->cmd, sizeof(struct tws_command_apache));
852         r->data = NULL;
853         r->length = 0;
854         r->type = type;
855         r->flags = TWS_DIR_UNKNOWN;
856         r->error_code = TWS_REQ_RET_INVALID;
857         r->cb = NULL;
858         r->ccb_ptr = NULL;
859         callout_stop(&r->timeout);
860         r->next = r->prev = NULL;
861
862         r->state = ((type == TWS_REQ_TYPE_SCSI_IO) ? TWS_REQ_STATE_TRAN : TWS_REQ_STATE_BUSY);
863     }
864
865     mtx_unlock(my_mutex);
866
867     return(r);
868 }
869
870 void
871 tws_release_request(struct tws_request *req)
872 {
873
874     struct tws_softc *sc = req->sc;
875
876     TWS_TRACE_DEBUG(sc, "entry", sc, 0);
877     mtx_lock(&sc->q_lock);
878     tws_q_insert_tail(sc, req, TWS_FREE_Q);
879     mtx_unlock(&sc->q_lock);
880 }
881
882 static device_method_t tws_methods[] = {
883     /* Device interface */
884     DEVMETHOD(device_probe,     tws_probe),
885     DEVMETHOD(device_attach,    tws_attach),
886     DEVMETHOD(device_detach,    tws_detach),
887     DEVMETHOD(device_shutdown,  tws_shutdown),
888     DEVMETHOD(device_suspend,   tws_suspend),
889     DEVMETHOD(device_resume,    tws_resume),
890
891     DEVMETHOD_END
892 };
893
894 static driver_t tws_driver = {
895         "tws",
896         tws_methods,
897         sizeof(struct tws_softc)
898 };
899
900
901 static devclass_t tws_devclass;
902
903 /* DEFINE_CLASS_0(tws, tws_driver, tws_methods, sizeof(struct tws_softc)); */
904 DRIVER_MODULE(tws, pci, tws_driver, tws_devclass, 0, 0);
905 MODULE_DEPEND(tws, cam, 1, 1, 1);
906 MODULE_DEPEND(tws, pci, 1, 1, 1);
907
908 TUNABLE_INT("hw.tws.queue_depth", &tws_queue_depth);
909 TUNABLE_INT("hw.tws.enable_msi", &tws_enable_msi);