2 * Copyright (c) 2018 Microsemi Corporation.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * CAM interface for smartpqi driver
32 #include "smartpqi_includes.h"
35 * Set cam sim properties of the smartpqi adapter.
37 static void update_sim_properties(struct cam_sim *sim, struct ccb_pathinq *cpi)
40 pqisrc_softstate_t *softs = (struct pqisrc_softstate *)
45 cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
47 cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED;
49 cpi->max_lun = PQI_MAX_MULTILUN;
50 cpi->max_target = 1088;
51 cpi->maxio = (softs->pqi_cap.max_sg_elem - 1) * PAGE_SIZE;
52 cpi->initiator_id = 255;
53 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
54 strncpy(cpi->hba_vid, "Microsemi", HBA_IDLEN);
55 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
56 cpi->unit_number = cam_sim_unit(sim);
57 cpi->bus_id = cam_sim_bus(sim);
58 cpi->base_transfer_speed = 1200000; /* Base bus speed in KB/sec */
59 cpi->protocol = PROTO_SCSI;
60 cpi->protocol_version = SCSI_REV_SPC4;
61 cpi->transport = XPORT_SPI;
62 cpi->transport_version = 2;
63 cpi->ccb_h.status = CAM_REQ_CMP;
69 * Get transport settings of the smartpqi adapter
71 static void get_transport_settings(struct pqisrc_softstate *softs,
72 struct ccb_trans_settings *cts)
74 struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi;
75 struct ccb_trans_settings_sas *sas = &cts->xport_specific.sas;
76 struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
80 cts->protocol = PROTO_SCSI;
81 cts->protocol_version = SCSI_REV_SPC4;
82 cts->transport = XPORT_SPI;
83 cts->transport_version = 2;
84 spi->valid = CTS_SPI_VALID_DISC;
85 spi->flags = CTS_SPI_FLAGS_DISC_ENB;
86 scsi->valid = CTS_SCSI_VALID_TQ;
87 scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
88 sas->valid = CTS_SAS_VALID_SPEED;
89 cts->ccb_h.status = CAM_REQ_CMP;
95 * Add the target to CAM layer and rescan, when a new device is found
97 void os_add_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) {
102 if(softs->os_specific.sim_registered) {
103 if ((ccb = xpt_alloc_ccb_nowait()) == NULL) {
104 DBG_ERR("rescan failed (can't allocate CCB)\n");
108 if (xpt_create_path(&ccb->ccb_h.path, NULL,
109 cam_sim_path(softs->os_specific.sim),
110 device->target, device->lun) != CAM_REQ_CMP) {
111 DBG_ERR("rescan failed (can't create path)\n");
122 * Remove the device from CAM layer when deleted or hot removed
124 void os_remove_device(pqisrc_softstate_t *softs,
125 pqi_scsi_dev_t *device) {
126 struct cam_path *tmppath;
130 if(softs->os_specific.sim_registered) {
131 if (xpt_create_path(&tmppath, NULL,
132 cam_sim_path(softs->os_specific.sim),
133 device->target, device->lun) != CAM_REQ_CMP) {
134 DBG_ERR("unable to create path for async event");
137 xpt_async(AC_LOST_DEVICE, tmppath, NULL);
138 xpt_free_path(tmppath);
139 pqisrc_free_device(softs, device);
147 * Function to release the frozen simq
149 static void pqi_release_camq( rcb_t *rcb )
151 pqisrc_softstate_t *softs;
152 struct ccb_scsiio *csio;
154 csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
159 if (softs->os_specific.pqi_flags & PQI_FLAG_BUSY) {
160 softs->os_specific.pqi_flags &= ~PQI_FLAG_BUSY;
161 if (csio->ccb_h.status & CAM_RELEASE_SIMQ)
162 xpt_release_simq(xpt_path_sim(csio->ccb_h.path), 0);
164 csio->ccb_h.status |= CAM_RELEASE_SIMQ;
171 * Function to dma-unmap the completed request
173 static void pqi_unmap_request(void *arg)
175 pqisrc_softstate_t *softs;
178 DBG_IO("IN rcb = %p\n", arg);
183 if (!(rcb->cm_flags & PQI_CMD_MAPPED))
186 if (rcb->bcount != 0 ) {
187 if (rcb->data_dir == SOP_DATA_DIR_FROM_DEVICE)
188 bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
190 BUS_DMASYNC_POSTREAD);
191 if (rcb->data_dir == SOP_DATA_DIR_TO_DEVICE)
192 bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
194 BUS_DMASYNC_POSTWRITE);
195 bus_dmamap_unload(softs->os_specific.pqi_buffer_dmat,
198 rcb->cm_flags &= ~PQI_CMD_MAPPED;
200 if(rcb->sgt && rcb->nseg)
201 os_mem_free(rcb->softs, (void*)rcb->sgt,
202 rcb->nseg*sizeof(sgt_t));
204 pqisrc_put_tag(&softs->taglist, rcb->tag);
210 * Construct meaningful LD name for volume here.
213 smartpqi_fix_ld_inquiry(pqisrc_softstate_t *softs, struct ccb_scsiio *csio)
215 struct scsi_inquiry_data *inq = NULL;
217 pqi_scsi_dev_t *device = NULL;
221 cdb = (csio->ccb_h.flags & CAM_CDB_POINTER) ?
222 (uint8_t *)csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes;
223 if(cdb[0] == INQUIRY &&
224 (cdb[1] & SI_EVPD) == 0 &&
225 (csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN &&
226 csio->dxfer_len >= SHORT_INQUIRY_LENGTH) {
227 inq = (struct scsi_inquiry_data *)csio->data_ptr;
229 device = softs->device_list[csio->ccb_h.target_id][csio->ccb_h.target_lun];
231 /* Let the disks be probed and dealt with via CAM. Only for LD
232 let it fall through and inquiry be tweaked */
233 if( !device || !pqisrc_is_logical_device(device) ||
234 (device->devtype != DISK_DEVICE) ||
235 pqisrc_is_external_raid_device(device)) {
239 strncpy(inq->vendor, "MSCC",
241 strncpy(inq->product,
242 pqisrc_raidlevel_to_string(device->raid_level),
244 strncpy(inq->revision, device->volume_offline?"OFF":"OK",
252 * Handle completion of a command - pass results back through the CCB
255 os_io_response_success(rcb_t *rcb)
257 struct ccb_scsiio *csio;
259 DBG_IO("IN rcb = %p\n", rcb);
262 panic("rcb is null");
264 csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
267 panic("csio is null");
269 rcb->status = REQUEST_SUCCESS;
270 csio->ccb_h.status = CAM_REQ_CMP;
272 smartpqi_fix_ld_inquiry(rcb->softs, csio);
273 pqi_release_camq(rcb);
274 pqi_unmap_request(rcb);
275 xpt_done((union ccb *)csio);
281 * Error response handling for raid IO
283 void os_raid_response_error(rcb_t *rcb, raid_path_error_info_elem_t *err_info)
285 struct ccb_scsiio *csio;
286 pqisrc_softstate_t *softs;
290 csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
293 panic("csio is null");
297 ASSERT(err_info != NULL);
298 csio->scsi_status = err_info->status;
299 csio->ccb_h.status = CAM_REQ_CMP_ERR;
301 if (csio->ccb_h.func_code == XPT_SCSI_IO) {
303 * Handle specific SCSI status values.
305 switch(csio->scsi_status) {
306 case PQI_RAID_STATUS_QUEUE_FULL:
307 csio->ccb_h.status = CAM_REQ_CMP;
308 DBG_ERR("Queue Full error");
310 /* check condition, sense data included */
311 case PQI_RAID_STATUS_CHECK_CONDITION:
313 uint16_t sense_data_len =
314 LE_16(err_info->sense_data_len);
315 uint8_t *sense_data = NULL;
317 sense_data = err_info->data;
318 memset(&csio->sense_data, 0, csio->sense_len);
319 sense_data_len = (sense_data_len >
324 memcpy(&csio->sense_data, sense_data,
326 if (csio->sense_len > sense_data_len)
327 csio->sense_resid = csio->sense_len
330 csio->sense_resid = 0;
331 csio->ccb_h.status = CAM_SCSI_STATUS_ERROR
337 case PQI_RAID_DATA_IN_OUT_UNDERFLOW:
340 resid = rcb->bcount-err_info->data_out_transferred;
342 csio->ccb_h.status = CAM_REQ_CMP;
346 csio->ccb_h.status = CAM_REQ_CMP;
351 if (softs->os_specific.pqi_flags & PQI_FLAG_BUSY) {
352 softs->os_specific.pqi_flags &= ~PQI_FLAG_BUSY;
353 if (csio->ccb_h.status & CAM_RELEASE_SIMQ)
354 xpt_release_simq(xpt_path_sim(csio->ccb_h.path), 0);
356 csio->ccb_h.status |= CAM_RELEASE_SIMQ;
359 pqi_unmap_request(rcb);
360 xpt_done((union ccb *)csio);
366 * Error response handling for aio.
368 void os_aio_response_error(rcb_t *rcb, aio_path_error_info_elem_t *err_info)
370 struct ccb_scsiio *csio;
371 pqisrc_softstate_t *softs;
376 panic("rcb is null");
378 rcb->status = REQUEST_SUCCESS;
379 csio = (struct ccb_scsiio *)&rcb->cm_ccb->csio;
381 panic("csio is null");
385 switch (err_info->service_resp) {
386 case PQI_AIO_SERV_RESPONSE_COMPLETE:
387 csio->ccb_h.status = err_info->status;
389 case PQI_AIO_SERV_RESPONSE_FAILURE:
390 switch(err_info->status) {
391 case PQI_AIO_STATUS_IO_ABORTED:
392 csio->ccb_h.status = CAM_REQ_ABORTED;
393 DBG_WARN_BTL(rcb->dvp, "IO aborted\n");
395 case PQI_AIO_STATUS_UNDERRUN:
396 csio->ccb_h.status = CAM_REQ_CMP;
398 LE_32(err_info->resd_count);
400 case PQI_AIO_STATUS_OVERRUN:
401 csio->ccb_h.status = CAM_REQ_CMP;
403 case PQI_AIO_STATUS_AIO_PATH_DISABLED:
404 DBG_WARN_BTL(rcb->dvp,"AIO Path Disabled\n");
405 rcb->dvp->offload_enabled = false;
406 csio->ccb_h.status |= CAM_REQUEUE_REQ;
408 case PQI_AIO_STATUS_IO_ERROR:
409 case PQI_AIO_STATUS_IO_NO_DEVICE:
410 case PQI_AIO_STATUS_INVALID_DEVICE:
412 DBG_WARN_BTL(rcb->dvp,"IO Error/Invalid/No device\n");
413 csio->ccb_h.status |=
414 CAM_SCSI_STATUS_ERROR;
418 case PQI_AIO_SERV_RESPONSE_TMF_COMPLETE:
419 case PQI_AIO_SERV_RESPONSE_TMF_SUCCEEDED:
420 csio->ccb_h.status = CAM_REQ_CMP;
422 case PQI_AIO_SERV_RESPONSE_TMF_REJECTED:
423 case PQI_AIO_SERV_RESPONSE_TMF_INCORRECT_LUN:
424 DBG_WARN_BTL(rcb->dvp,"TMF rejected/Incorrect Lun\n");
425 csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
428 DBG_WARN_BTL(rcb->dvp,"Scsi Status Error\n");
429 csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
432 if(err_info->data_pres == DATA_PRESENT_SENSE_DATA ) {
433 csio->scsi_status = PQI_AIO_STATUS_CHECK_CONDITION;
434 uint8_t *sense_data = NULL;
435 unsigned sense_data_len = LE_16(err_info->data_len);
437 sense_data = err_info->data;
438 DBG_ERR_BTL(rcb->dvp, "SCSI_STATUS_CHECK_COND sense size %u\n",
440 memset(&csio->sense_data, 0, csio->sense_len);
442 memcpy(&csio->sense_data, sense_data, ((sense_data_len >
443 csio->sense_len) ? csio->sense_len : sense_data_len));
444 if (csio->sense_len > sense_data_len)
445 csio->sense_resid = csio->sense_len - sense_data_len;
447 csio->sense_resid = 0;
448 csio->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
451 smartpqi_fix_ld_inquiry(softs, csio);
452 pqi_release_camq(rcb);
453 pqi_unmap_request(rcb);
454 xpt_done((union ccb *)csio);
459 pqi_freeze_ccb(union ccb *ccb)
461 if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
462 ccb->ccb_h.status |= CAM_DEV_QFRZN;
463 xpt_freeze_devq(ccb->ccb_h.path, 1);
468 * Command-mapping helper function - populate this command's s/g table.
471 pqi_request_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
473 pqisrc_softstate_t *softs;
479 if( error || nseg > softs->pqi_cap.max_sg_elem )
481 rcb->cm_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
482 pqi_freeze_ccb(rcb->cm_ccb);
483 DBG_ERR_BTL(rcb->dvp, "map failed err = %d or nseg(%d) > sgelem(%d)\n",
484 error, nseg, softs->pqi_cap.max_sg_elem);
485 pqi_unmap_request(rcb);
486 xpt_done((union ccb *)rcb->cm_ccb);
490 rcb->sgt = os_mem_alloc(softs, nseg * sizeof(rcb_t));
491 if (rcb->sgt == NULL) {
492 rcb->cm_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
493 pqi_freeze_ccb(rcb->cm_ccb);
494 DBG_ERR_BTL(rcb->dvp, "os_mem_alloc() failed; nseg = %d\n", nseg);
495 pqi_unmap_request(rcb);
496 xpt_done((union ccb *)rcb->cm_ccb);
501 for (int i = 0; i < nseg; i++) {
502 rcb->sgt[i].addr = segs[i].ds_addr;
503 rcb->sgt[i].len = segs[i].ds_len;
504 rcb->sgt[i].flags = 0;
507 if (rcb->data_dir == SOP_DATA_DIR_FROM_DEVICE)
508 bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
509 rcb->cm_datamap, BUS_DMASYNC_PREREAD);
510 if (rcb->data_dir == SOP_DATA_DIR_TO_DEVICE)
511 bus_dmamap_sync(softs->os_specific.pqi_buffer_dmat,
512 rcb->cm_datamap, BUS_DMASYNC_PREWRITE);
514 /* Call IO functions depending on pd or ld */
515 rcb->status = REQUEST_PENDING;
517 error = pqisrc_build_send_io(softs, rcb);
520 rcb->req_pending = false;
521 rcb->cm_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
522 pqi_freeze_ccb(rcb->cm_ccb);
523 DBG_ERR_BTL(rcb->dvp, "Build IO failed, error = %d\n", error);
524 pqi_unmap_request(rcb);
525 xpt_done((union ccb *)rcb->cm_ccb);
531 * Function to dma-map the request buffer
533 static int pqi_map_request( rcb_t *rcb )
535 pqisrc_softstate_t *softs = rcb->softs;
536 int error = PQI_STATUS_SUCCESS;
537 union ccb *ccb = rcb->cm_ccb;
541 /* check that mapping is necessary */
542 if (rcb->cm_flags & PQI_CMD_MAPPED)
544 rcb->cm_flags |= PQI_CMD_MAPPED;
547 error = bus_dmamap_load_ccb(softs->os_specific.pqi_buffer_dmat,
548 rcb->cm_datamap, ccb, pqi_request_map_helper, rcb, 0);
550 DBG_ERR_BTL(rcb->dvp, "bus_dmamap_load_ccb failed = %d count = %d\n",
556 * Set up the command to go to the controller. If there are no
557 * data buffers associated with the command then it can bypass
560 /* Call IO functions depending on pd or ld */
561 rcb->status = REQUEST_PENDING;
563 error = pqisrc_build_send_io(softs, rcb);
566 DBG_FUNC("OUT error = %d\n", error);
572 * Function to clear the request control block
574 void os_reset_rcb( rcb_t *rcb )
576 rcb->error_info = NULL;
579 rcb->tag = INVALID_ELEM;
589 rcb->encrypt_enable = false;
590 rcb->ioaccel_handle = 0;
592 rcb->req_pending = false;
596 * Callback function for the lun rescan
598 static void smartpqi_lunrescan_cb(struct cam_periph *periph, union ccb *ccb)
600 xpt_free_path(ccb->ccb_h.path);
605 * Function to rescan the lun
607 static void smartpqi_lun_rescan(struct pqisrc_softstate *softs, int target,
610 union ccb *ccb = NULL;
611 cam_status status = 0;
612 struct cam_path *path = NULL;
616 ccb = xpt_alloc_ccb_nowait();
617 status = xpt_create_path(&path, NULL,
618 cam_sim_path(softs->os_specific.sim), target, lun);
619 if (status != CAM_REQ_CMP) {
620 DBG_ERR("xpt_create_path status(%d) != CAM_REQ_CMP \n",
626 bzero(ccb, sizeof(union ccb));
627 xpt_setup_ccb(&ccb->ccb_h, path, 5);
628 ccb->ccb_h.func_code = XPT_SCAN_LUN;
629 ccb->ccb_h.cbfcnp = smartpqi_lunrescan_cb;
630 ccb->crcn.flags = CAM_FLAG_NONE;
638 * Function to rescan the lun under each target
640 void smartpqi_target_rescan(struct pqisrc_softstate *softs)
642 int target = 0, lun = 0;
646 for(target = 0; target < PQI_MAX_DEVICES; target++){
647 for(lun = 0; lun < PQI_MAX_MULTILUN; lun++){
648 if(softs->device_list[target][lun]){
649 smartpqi_lun_rescan(softs, target, lun);
658 * Set the mode of tagged command queueing for the current task.
660 uint8_t os_get_task_attr(rcb_t *rcb)
662 union ccb *ccb = rcb->cm_ccb;
663 uint8_t tag_action = SOP_TASK_ATTRIBUTE_SIMPLE;
665 switch(ccb->csio.tag_action) {
666 case MSG_HEAD_OF_Q_TAG:
667 tag_action = SOP_TASK_ATTRIBUTE_HEAD_OF_QUEUE;
669 case MSG_ORDERED_Q_TAG:
670 tag_action = SOP_TASK_ATTRIBUTE_ORDERED;
672 case MSG_SIMPLE_Q_TAG:
674 tag_action = SOP_TASK_ATTRIBUTE_SIMPLE;
681 * Complete all outstanding commands
683 void os_complete_outstanding_cmds_nodevice(pqisrc_softstate_t *softs)
689 for (tag = 1; tag < softs->max_outstanding_io; tag++) {
690 rcb_t *prcb = &softs->rcb[tag];
691 if(prcb->req_pending && prcb->cm_ccb ) {
692 prcb->req_pending = false;
693 prcb->cm_ccb->ccb_h.status = CAM_REQ_ABORTED | CAM_REQ_CMP;
694 xpt_done((union ccb *)prcb->cm_ccb);
703 * IO handling functionality entry point
705 static int pqisrc_io_start(struct cam_sim *sim, union ccb *ccb)
708 uint32_t tag, no_transfer = 0;
709 pqisrc_softstate_t *softs = (struct pqisrc_softstate *)
711 int32_t error = PQI_STATUS_FAILURE;
716 if( softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun] == NULL ) {
717 ccb->ccb_h.status = CAM_DEV_NOT_THERE;
718 DBG_INFO("Device = %d not there\n", ccb->ccb_h.target_id);
719 return PQI_STATUS_FAILURE;
722 dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun];
723 /* Check controller state */
724 if (IN_PQI_RESET(softs)) {
725 ccb->ccb_h.status = CAM_SCSI_BUS_RESET
726 | CAM_BUSY | CAM_REQ_INPROG;
727 DBG_WARN("Device = %d BUSY/IN_RESET\n", ccb->ccb_h.target_id);
730 /* Check device state */
731 if (pqisrc_ctrl_offline(softs) || DEV_GONE(dvp)) {
732 ccb->ccb_h.status = CAM_DEV_NOT_THERE | CAM_REQ_CMP;
733 DBG_WARN("Device = %d GONE/OFFLINE\n", ccb->ccb_h.target_id);
736 /* Check device reset */
737 if (dvp->reset_in_progress) {
738 ccb->ccb_h.status = CAM_SCSI_BUSY | CAM_REQ_INPROG | CAM_BUSY;
739 DBG_WARN("Device %d reset returned busy\n", ccb->ccb_h.target_id);
743 if (dvp->expose_device == false) {
744 ccb->ccb_h.status = CAM_DEV_NOT_THERE;
745 DBG_INFO("Device = %d not exposed\n", ccb->ccb_h.target_id);
749 tag = pqisrc_get_tag(&softs->taglist);
750 if( tag == INVALID_ELEM ) {
751 DBG_ERR("Get Tag failed\n");
752 xpt_freeze_simq(softs->os_specific.sim, 1);
753 softs->os_specific.pqi_flags |= PQI_FLAG_BUSY;
754 ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_RELEASE_SIMQ);
755 return PQI_STATUS_FAILURE;
758 DBG_IO("tag = %d &softs->taglist : %p\n", tag, &softs->taglist);
760 rcb = &softs->rcb[tag];
764 rcb->cmdlen = ccb->csio.cdb_len;
765 ccb->ccb_h.sim_priv.entries[0].ptr = rcb;
767 switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
769 rcb->data_dir = SOP_DATA_DIR_FROM_DEVICE;
772 rcb->data_dir = SOP_DATA_DIR_TO_DEVICE;
778 DBG_ERR("Unknown Dir\n");
782 rcb->dvp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun];
785 rcb->cm_data = (void *)ccb->csio.data_ptr;
786 rcb->bcount = ccb->csio.dxfer_len;
792 * Submit the request to the adapter.
794 * Note that this may fail if we're unable to map the request (and
795 * if we ever learn a transport layer other than simple, may fail
796 * if the adapter rejects the command).
798 if ((error = pqi_map_request(rcb)) != 0) {
799 rcb->req_pending = false;
800 xpt_freeze_simq(softs->os_specific.sim, 1);
801 ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
802 if (error == EINPROGRESS) {
803 DBG_WARN("In Progress on %d\n", ccb->ccb_h.target_id);
806 ccb->ccb_h.status |= CAM_REQUEUE_REQ;
807 DBG_WARN("Requeue req error = %d target = %d\n", error,
808 ccb->ccb_h.target_id);
809 pqi_unmap_request(rcb);
813 DBG_FUNC("OUT error = %d\n", error);
818 * Abort a task, task management functionality
821 pqisrc_scsi_abort_task(pqisrc_softstate_t *softs, union ccb *ccb)
823 rcb_t *rcb = ccb->ccb_h.sim_priv.entries[0].ptr;
824 uint32_t abort_tag = rcb->tag;
826 int rval = PQI_STATUS_SUCCESS;
831 qid = (uint16_t)rcb->resp_qid;
833 tag = pqisrc_get_tag(&softs->taglist);
834 rcb = &softs->rcb[tag];
838 rval = pqisrc_send_tmf(softs, rcb->dvp, rcb, abort_tag,
839 SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK);
841 if (PQI_STATUS_SUCCESS == rval) {
843 if (REQUEST_SUCCESS == rval) {
844 ccb->ccb_h.status = CAM_REQ_ABORTED;
847 pqisrc_put_tag(&softs->taglist, abort_tag);
848 pqisrc_put_tag(&softs->taglist,rcb->tag);
850 DBG_FUNC("OUT rval = %d\n", rval);
856 * Abort a taskset, task management functionality
859 pqisrc_scsi_abort_task_set(pqisrc_softstate_t *softs, union ccb *ccb)
863 int rval = PQI_STATUS_SUCCESS;
867 tag = pqisrc_get_tag(&softs->taglist);
868 rcb = &softs->rcb[tag];
871 rval = pqisrc_send_tmf(softs, rcb->dvp, rcb, 0,
872 SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK_SET);
874 if (rval == PQI_STATUS_SUCCESS) {
878 pqisrc_put_tag(&softs->taglist,rcb->tag);
880 DBG_FUNC("OUT rval = %d\n", rval);
886 * Target reset task management functionality
889 pqisrc_target_reset( pqisrc_softstate_t *softs, union ccb *ccb)
891 pqi_scsi_dev_t *devp = softs->device_list[ccb->ccb_h.target_id][ccb->ccb_h.target_lun];
894 int rval = PQI_STATUS_SUCCESS;
899 DBG_ERR("bad target t%d\n", ccb->ccb_h.target_id);
903 tag = pqisrc_get_tag(&softs->taglist);
904 rcb = &softs->rcb[tag];
907 devp->reset_in_progress = true;
908 rval = pqisrc_send_tmf(softs, devp, rcb, 0,
909 SOP_TASK_MANAGEMENT_LUN_RESET);
910 if (PQI_STATUS_SUCCESS == rval) {
913 devp->reset_in_progress = false;
914 pqisrc_put_tag(&softs->taglist,rcb->tag);
916 DBG_FUNC("OUT rval = %d\n", rval);
918 return ((rval == REQUEST_SUCCESS) ?
919 PQI_STATUS_SUCCESS : PQI_STATUS_FAILURE);
923 * cam entry point of the smartpqi module.
925 static void smartpqi_cam_action(struct cam_sim *sim, union ccb *ccb)
927 struct pqisrc_softstate *softs = cam_sim_softc(sim);
928 struct ccb_hdr *ccb_h = &ccb->ccb_h;
932 switch (ccb_h->func_code) {
935 if(!pqisrc_io_start(sim, ccb)) {
940 case XPT_CALC_GEOMETRY:
942 struct ccb_calc_geometry *ccg;
944 if (ccg->block_size == 0) {
945 ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
946 ccb->ccb_h.status = CAM_REQ_INVALID;
949 cam_calc_geometry(ccg, /* extended */ 1);
950 ccb->ccb_h.status = CAM_REQ_CMP;
955 update_sim_properties(sim, &ccb->cpi);
956 ccb->ccb_h.status = CAM_REQ_CMP;
959 case XPT_GET_TRAN_SETTINGS:
960 get_transport_settings(softs, &ccb->cts);
961 ccb->ccb_h.status = CAM_REQ_CMP;
964 if(pqisrc_scsi_abort_task(softs, ccb)) {
965 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
967 DBG_ERR("Abort task failed on %d\n",
968 ccb->ccb_h.target_id);
973 if (pqisrc_scsi_abort_task_set(softs, ccb)) {
974 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
975 DBG_ERR("Abort task set failed on %d\n",
976 ccb->ccb_h.target_id);
982 if(pqisrc_target_reset(softs, ccb)) {
983 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
984 DBG_ERR("Target reset failed on %d\n",
985 ccb->ccb_h.target_id);
989 ccb->ccb_h.status = CAM_REQ_CMP;
993 ccb->ccb_h.status = CAM_REQ_CMP;
995 case XPT_SET_TRAN_SETTINGS:
996 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
999 DBG_WARN("UNSUPPORTED FUNC CODE\n");
1000 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1009 * Function to poll the response, when interrupts are unavailable
1010 * This also serves supporting crash dump.
1012 static void smartpqi_poll(struct cam_sim *sim)
1014 struct pqisrc_softstate *softs = cam_sim_softc(sim);
1017 for (i = 1; i < softs->intr_count; i++ )
1018 pqisrc_process_response_queue(softs, i);
1022 * Function to adjust the queue depth of a device
1024 void smartpqi_adjust_queue_depth(struct cam_path *path, uint32_t queue_depth)
1026 struct ccb_relsim crs;
1030 xpt_setup_ccb(&crs.ccb_h, path, 5);
1031 crs.ccb_h.func_code = XPT_REL_SIMQ;
1032 crs.ccb_h.flags = CAM_DEV_QFREEZE;
1033 crs.release_flags = RELSIM_ADJUST_OPENINGS;
1034 crs.openings = queue_depth;
1035 xpt_action((union ccb *)&crs);
1036 if(crs.ccb_h.status != CAM_REQ_CMP) {
1037 printf("XPT_REL_SIMQ failed stat=%d\n", crs.ccb_h.status);
1044 * Function to register async callback for setting queue depth
1047 smartpqi_async(void *callback_arg, u_int32_t code,
1048 struct cam_path *path, void *arg)
1050 struct pqisrc_softstate *softs;
1051 softs = (struct pqisrc_softstate*)callback_arg;
1056 case AC_FOUND_DEVICE:
1058 struct ccb_getdev *cgd;
1059 cgd = (struct ccb_getdev *)arg;
1063 uint32_t t_id = cgd->ccb_h.target_id;
1065 if (t_id <= (PQI_CTLR_INDEX - 1)) {
1066 if (softs != NULL) {
1067 pqi_scsi_dev_t *dvp = softs->device_list[t_id][cgd->ccb_h.target_lun];
1068 smartpqi_adjust_queue_depth(path,
1082 * Function to register sim with CAM layer for smartpqi driver
1084 int register_sim(struct pqisrc_softstate *softs, int card_index)
1087 int max_transactions;
1088 union ccb *ccb = NULL;
1089 cam_status status = 0;
1090 struct ccb_setasync csa;
1091 struct cam_sim *sim;
1095 max_transactions = softs->max_io_for_scsi_ml;
1096 softs->os_specific.devq = cam_simq_alloc(max_transactions);
1097 if (softs->os_specific.devq == NULL) {
1098 DBG_ERR("cam_simq_alloc failed txns = %d\n",
1100 return PQI_STATUS_FAILURE;
1103 sim = cam_sim_alloc(smartpqi_cam_action, \
1104 smartpqi_poll, "smartpqi", softs, \
1105 card_index, &softs->os_specific.cam_lock, \
1106 1, max_transactions, softs->os_specific.devq);
1108 DBG_ERR("cam_sim_alloc failed txns = %d\n",
1110 cam_simq_free(softs->os_specific.devq);
1111 return PQI_STATUS_FAILURE;
1114 softs->os_specific.sim = sim;
1115 mtx_lock(&softs->os_specific.cam_lock);
1116 status = xpt_bus_register(sim, softs->os_specific.pqi_dev, 0);
1117 if (status != CAM_SUCCESS) {
1118 DBG_ERR("xpt_bus_register failed status=%d\n", status);
1119 cam_sim_free(softs->os_specific.sim, FALSE);
1120 cam_simq_free(softs->os_specific.devq);
1121 mtx_unlock(&softs->os_specific.cam_lock);
1122 return PQI_STATUS_FAILURE;
1125 softs->os_specific.sim_registered = TRUE;
1126 ccb = xpt_alloc_ccb_nowait();
1128 DBG_ERR("xpt_create_path failed\n");
1129 return PQI_STATUS_FAILURE;
1132 if (xpt_create_path(&ccb->ccb_h.path, NULL,
1133 cam_sim_path(softs->os_specific.sim),
1134 CAM_TARGET_WILDCARD,
1135 CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1136 DBG_ERR("xpt_create_path failed\n");
1138 xpt_bus_deregister(cam_sim_path(softs->os_specific.sim));
1139 cam_sim_free(softs->os_specific.sim, TRUE);
1140 mtx_unlock(&softs->os_specific.cam_lock);
1141 return PQI_STATUS_FAILURE;
1144 * Callback to set the queue depth per target which is
1145 * derived from the FW.
1147 softs->os_specific.path = ccb->ccb_h.path;
1148 xpt_setup_ccb(&csa.ccb_h, softs->os_specific.path, 5);
1149 csa.ccb_h.func_code = XPT_SASYNC_CB;
1150 csa.event_enable = AC_FOUND_DEVICE;
1151 csa.callback = smartpqi_async;
1152 csa.callback_arg = softs;
1153 xpt_action((union ccb *)&csa);
1154 if (csa.ccb_h.status != CAM_REQ_CMP) {
1155 DBG_ERR("Unable to register smartpqi_aysnc handler: %d!\n",
1159 mtx_unlock(&softs->os_specific.cam_lock);
1165 * Function to deregister smartpqi sim from cam layer
1167 void deregister_sim(struct pqisrc_softstate *softs)
1169 struct ccb_setasync csa;
1173 if (softs->os_specific.mtx_init) {
1174 mtx_lock(&softs->os_specific.cam_lock);
1177 xpt_setup_ccb(&csa.ccb_h, softs->os_specific.path, 5);
1178 csa.ccb_h.func_code = XPT_SASYNC_CB;
1179 csa.event_enable = 0;
1180 csa.callback = smartpqi_async;
1181 csa.callback_arg = softs;
1182 xpt_action((union ccb *)&csa);
1183 xpt_free_path(softs->os_specific.path);
1185 xpt_release_simq(softs->os_specific.sim, 0);
1187 xpt_bus_deregister(cam_sim_path(softs->os_specific.sim));
1188 softs->os_specific.sim_registered = FALSE;
1190 if (softs->os_specific.sim) {
1191 cam_sim_free(softs->os_specific.sim, FALSE);
1192 softs->os_specific.sim = NULL;
1194 if (softs->os_specific.mtx_init) {
1195 mtx_unlock(&softs->os_specific.cam_lock);
1197 if (softs->os_specific.devq != NULL) {
1198 cam_simq_free(softs->os_specific.devq);
1200 if (softs->os_specific.mtx_init) {
1201 mtx_destroy(&softs->os_specific.cam_lock);
1202 softs->os_specific.mtx_init = FALSE;
1205 mtx_destroy(&softs->os_specific.map_lock);