1250963Sachim/*- 2250963Sachim * Copyright (c) 2002-2010 Adaptec, Inc. 3250963Sachim * Copyright (c) 2010-2012 PMC-Sierra, Inc. 4250963Sachim * All rights reserved. 5250963Sachim * 6250963Sachim * Redistribution and use in source and binary forms, with or without 7250963Sachim * modification, are permitted provided that the following conditions 8250963Sachim * are met: 9250963Sachim * 1. Redistributions of source code must retain the above copyright 10250963Sachim * notice, this list of conditions and the following disclaimer. 11250963Sachim * 2. Redistributions in binary form must reproduce the above copyright 12250963Sachim * notice, this list of conditions and the following disclaimer in the 13250963Sachim * documentation and/or other materials provided with the distribution. 14250963Sachim * 15250963Sachim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16250963Sachim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17250963Sachim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18250963Sachim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19250963Sachim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20250963Sachim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21250963Sachim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22250963Sachim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23250963Sachim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24250963Sachim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25250963Sachim * SUCH DAMAGE. 26250963Sachim */ 27250963Sachim 28250963Sachim#include <sys/cdefs.h> 29250963Sachim__FBSDID("$FreeBSD: stable/10/sys/dev/aacraid/aacraid_cam.c 316857 2017-04-14 16:40:10Z avg $"); 30250963Sachim 31250963Sachim/* 32250963Sachim * CAM front-end for communicating with non-DASD devices 33250963Sachim */ 34250963Sachim 35250963Sachim#include "opt_aacraid.h" 36250963Sachim 37250963Sachim#include <sys/param.h> 38250963Sachim#include <sys/systm.h> 39250963Sachim#include <sys/kernel.h> 40250963Sachim#include <sys/sysctl.h> 41250963Sachim#include <sys/lock.h> 42250963Sachim#include <sys/malloc.h> 43250963Sachim#include <sys/module.h> 44250963Sachim#include <sys/mutex.h> 45250963Sachim 46250963Sachim#include <cam/cam.h> 47250963Sachim#include <cam/cam_ccb.h> 48250963Sachim#include <cam/cam_debug.h> 49250963Sachim#include <cam/cam_periph.h> 50250963Sachim#if __FreeBSD_version < 801000 51250963Sachim#include <cam/cam_xpt_periph.h> 52250963Sachim#endif 53250963Sachim#include <cam/cam_sim.h> 54250963Sachim#include <cam/cam_xpt_sim.h> 55250963Sachim#include <cam/scsi/scsi_all.h> 56250963Sachim#include <cam/scsi/scsi_message.h> 57250963Sachim 58250963Sachim#include <sys/bus.h> 59250963Sachim#include <sys/conf.h> 60250963Sachim#include <sys/disk.h> 61250963Sachim 62250963Sachim#include <machine/md_var.h> 63250963Sachim#include <machine/bus.h> 64250963Sachim#include <sys/rman.h> 65250963Sachim 66250963Sachim#include <vm/vm.h> 67250963Sachim#include <vm/pmap.h> 68250963Sachim 69250963Sachim#include <dev/aacraid/aacraid_reg.h> 70250963Sachim#include <sys/aac_ioctl.h> 71250963Sachim#include <dev/aacraid/aacraid_debug.h> 72250963Sachim#include <dev/aacraid/aacraid_var.h> 73250963Sachim 74250963Sachim#if __FreeBSD_version >= 700025 75250963Sachim#ifndef CAM_NEW_TRAN_CODE 76250963Sachim#define CAM_NEW_TRAN_CODE 1 77250963Sachim#endif 78250963Sachim#endif 79250963Sachim 80250963Sachim#ifndef SVPD_SUPPORTED_PAGE_LIST 81250963Sachimstruct scsi_vpd_supported_page_list 82250963Sachim{ 83250963Sachim u_int8_t device; 84250963Sachim u_int8_t page_code; 85250963Sachim#define SVPD_SUPPORTED_PAGE_LIST 0x00 86250963Sachim u_int8_t reserved; 87250963Sachim u_int8_t length; /* number of VPD entries */ 88250963Sachim#define SVPD_SUPPORTED_PAGES_SIZE 251 89250963Sachim u_int8_t list[SVPD_SUPPORTED_PAGES_SIZE]; 90250963Sachim}; 91250963Sachim#endif 92250963Sachim 93250963Sachim/************************** Version Compatibility *************************/ 94250963Sachim#if __FreeBSD_version < 700031 95250963Sachim#define aac_sim_alloc(a,b,c,d,e,f,g,h,i) cam_sim_alloc(a,b,c,d,e,g,h,i) 96250963Sachim#else 97250963Sachim#define aac_sim_alloc cam_sim_alloc 98250963Sachim#endif 99250963Sachim 100250963Sachimstruct aac_cam { 101250963Sachim device_t dev; 102250963Sachim struct aac_sim *inf; 103250963Sachim struct cam_sim *sim; 104250963Sachim struct cam_path *path; 105250963Sachim}; 106250963Sachim 107250963Sachimstatic int aac_cam_probe(device_t dev); 108250963Sachimstatic int aac_cam_attach(device_t dev); 109250963Sachimstatic int aac_cam_detach(device_t dev); 110250963Sachimstatic void aac_cam_action(struct cam_sim *, union ccb *); 111250963Sachimstatic void aac_cam_poll(struct cam_sim *); 112250963Sachimstatic void aac_cam_complete(struct aac_command *); 113250963Sachimstatic void aac_container_complete(struct aac_command *); 114250963Sachim#if __FreeBSD_version >= 700000 115250963Sachimstatic void aac_cam_rescan(struct aac_softc *sc, uint32_t channel, 116250963Sachim uint32_t target_id); 117250963Sachim#endif 118250963Sachimstatic void aac_set_scsi_error(struct aac_softc *sc, union ccb *ccb, 119250963Sachim u_int8_t status, u_int8_t key, u_int8_t asc, u_int8_t ascq); 120250963Sachimstatic int aac_load_map_command_sg(struct aac_softc *, struct aac_command *); 121250963Sachimstatic u_int64_t aac_eval_blockno(u_int8_t *); 122250963Sachimstatic void aac_container_rw_command(struct cam_sim *, union ccb *, u_int8_t *); 123250963Sachimstatic void aac_container_special_command(struct cam_sim *, union ccb *, 124250963Sachim u_int8_t *); 125250963Sachimstatic void aac_passthrough_command(struct cam_sim *, union ccb *); 126250963Sachim 127250963Sachimstatic u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *); 128250963Sachimstatic u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *); 129250963Sachimstatic u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *); 130250963Sachim 131250963Sachimstatic devclass_t aacraid_pass_devclass; 132250963Sachim 133250963Sachimstatic device_method_t aacraid_pass_methods[] = { 134250963Sachim DEVMETHOD(device_probe, aac_cam_probe), 135250963Sachim DEVMETHOD(device_attach, aac_cam_attach), 136250963Sachim DEVMETHOD(device_detach, aac_cam_detach), 137250963Sachim { 0, 0 } 138250963Sachim}; 139250963Sachim 140250963Sachimstatic driver_t aacraid_pass_driver = { 141250963Sachim "aacraidp", 142250963Sachim aacraid_pass_methods, 143250963Sachim sizeof(struct aac_cam) 144250963Sachim}; 145250963Sachim 146250963SachimDRIVER_MODULE(aacraidp, aacraid, aacraid_pass_driver, aacraid_pass_devclass, 0, 0); 147250963SachimMODULE_DEPEND(aacraidp, cam, 1, 1, 1); 148250963Sachim 149250963SachimMALLOC_DEFINE(M_AACRAIDCAM, "aacraidcam", "AACRAID CAM info"); 150250963Sachim 151250963Sachimstatic void 152250963Sachimaac_set_scsi_error(struct aac_softc *sc, union ccb *ccb, u_int8_t status, 153250963Sachim u_int8_t key, u_int8_t asc, u_int8_t ascq) 154250963Sachim{ 155250963Sachim#if __FreeBSD_version >= 900000 156250963Sachim struct scsi_sense_data_fixed *sense = 157250963Sachim (struct scsi_sense_data_fixed *)&ccb->csio.sense_data; 158250963Sachim#else 159250963Sachim struct scsi_sense_data *sense = &ccb->csio.sense_data; 160250963Sachim#endif 161250963Sachim 162250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "Error %d!", status); 163250963Sachim 164250963Sachim ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 165250963Sachim ccb->csio.scsi_status = status; 166250963Sachim if (status == SCSI_STATUS_CHECK_COND) { 167250963Sachim ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 168250963Sachim bzero(&ccb->csio.sense_data, ccb->csio.sense_len); 169250963Sachim ccb->csio.sense_data.error_code = 170250963Sachim SSD_CURRENT_ERROR | SSD_ERRCODE_VALID; 171250963Sachim sense->flags = key; 172250963Sachim if (ccb->csio.sense_len >= 14) { 173250963Sachim sense->extra_len = 6; 174250963Sachim sense->add_sense_code = asc; 175250963Sachim sense->add_sense_code_qual = ascq; 176250963Sachim } 177250963Sachim } 178250963Sachim} 179250963Sachim 180250963Sachim#if __FreeBSD_version >= 700000 181250963Sachimstatic void 182250963Sachimaac_cam_rescan(struct aac_softc *sc, uint32_t channel, uint32_t target_id) 183250963Sachim{ 184250963Sachim union ccb *ccb; 185250963Sachim struct aac_sim *sim; 186250963Sachim struct aac_cam *camsc; 187250963Sachim 188250963Sachim if (target_id == AAC_CAM_TARGET_WILDCARD) 189250963Sachim target_id = CAM_TARGET_WILDCARD; 190250963Sachim 191250963Sachim TAILQ_FOREACH(sim, &sc->aac_sim_tqh, sim_link) { 192250963Sachim camsc = sim->aac_cam; 193250963Sachim if (camsc == NULL || camsc->inf == NULL || 194250963Sachim camsc->inf->BusNumber != channel) 195250963Sachim continue; 196250963Sachim 197250963Sachim ccb = xpt_alloc_ccb_nowait(); 198250963Sachim if (ccb == NULL) { 199250963Sachim device_printf(sc->aac_dev, 200250963Sachim "Cannot allocate ccb for bus rescan.\n"); 201250963Sachim return; 202250963Sachim } 203250963Sachim 204250963Sachim if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, 205250963Sachim cam_sim_path(camsc->sim), 206250963Sachim target_id, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 207250963Sachim xpt_free_ccb(ccb); 208250963Sachim device_printf(sc->aac_dev, 209250963Sachim "Cannot create path for bus rescan.\n"); 210250963Sachim return; 211250963Sachim } 212250963Sachim xpt_rescan(ccb); 213250963Sachim break; 214250963Sachim } 215250963Sachim} 216250963Sachim#endif 217250963Sachim 218250963Sachimstatic void 219250963Sachimaac_cam_event(struct aac_softc *sc, struct aac_event *event, void *arg) 220250963Sachim{ 221250963Sachim union ccb *ccb; 222250963Sachim struct aac_cam *camsc; 223250963Sachim 224250963Sachim switch (event->ev_type) { 225250963Sachim case AAC_EVENT_CMFREE: 226250963Sachim ccb = arg; 227250963Sachim camsc = ccb->ccb_h.sim_priv.entries[0].ptr; 228250963Sachim free(event, M_AACRAIDCAM); 229250963Sachim xpt_release_simq(camsc->sim, 1); 230250963Sachim ccb->ccb_h.status = CAM_REQUEUE_REQ; 231250963Sachim xpt_done(ccb); 232250963Sachim break; 233250963Sachim default: 234250963Sachim device_printf(sc->aac_dev, "unknown event %d in aac_cam\n", 235250963Sachim event->ev_type); 236250963Sachim break; 237250963Sachim } 238250963Sachim 239250963Sachim return; 240250963Sachim} 241250963Sachim 242250963Sachimstatic int 243250963Sachimaac_cam_probe(device_t dev) 244250963Sachim{ 245250963Sachim struct aac_cam *camsc; 246250963Sachim 247250963Sachim camsc = (struct aac_cam *)device_get_softc(dev); 248250963Sachim if (!camsc->inf) 249250963Sachim return (0); 250316846Savg fwprintf(camsc->inf->aac_sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 251250963Sachim return (0); 252250963Sachim} 253250963Sachim 254250963Sachimstatic int 255250963Sachimaac_cam_detach(device_t dev) 256250963Sachim{ 257250963Sachim struct aac_softc *sc; 258250963Sachim struct aac_cam *camsc; 259250963Sachim 260250963Sachim camsc = (struct aac_cam *)device_get_softc(dev); 261250963Sachim if (!camsc->inf) 262250963Sachim return (0); 263250963Sachim sc = camsc->inf->aac_sc; 264250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 265250963Sachim camsc->inf->aac_cam = NULL; 266250963Sachim 267250963Sachim mtx_lock(&sc->aac_io_lock); 268250963Sachim 269250963Sachim xpt_async(AC_LOST_DEVICE, camsc->path, NULL); 270250963Sachim xpt_free_path(camsc->path); 271250963Sachim xpt_bus_deregister(cam_sim_path(camsc->sim)); 272250963Sachim cam_sim_free(camsc->sim, /*free_devq*/TRUE); 273250963Sachim 274250963Sachim sc->cam_rescan_cb = NULL; 275250963Sachim 276250963Sachim mtx_unlock(&sc->aac_io_lock); 277250963Sachim 278250963Sachim return (0); 279250963Sachim} 280250963Sachim 281250963Sachim/* 282250963Sachim * Register the driver as a CAM SIM 283250963Sachim */ 284250963Sachimstatic int 285250963Sachimaac_cam_attach(device_t dev) 286250963Sachim{ 287250963Sachim struct cam_devq *devq; 288250963Sachim struct cam_sim *sim; 289250963Sachim struct cam_path *path; 290250963Sachim struct aac_cam *camsc; 291250963Sachim struct aac_sim *inf; 292250963Sachim 293250963Sachim camsc = (struct aac_cam *)device_get_softc(dev); 294250963Sachim inf = (struct aac_sim *)device_get_ivars(dev); 295250963Sachim if (!inf) 296250963Sachim return (EIO); 297250963Sachim fwprintf(inf->aac_sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 298250963Sachim camsc->inf = inf; 299250963Sachim camsc->inf->aac_cam = camsc; 300250963Sachim 301250963Sachim devq = cam_simq_alloc(inf->TargetsPerBus); 302250963Sachim if (devq == NULL) 303250963Sachim return (EIO); 304250963Sachim 305250963Sachim sim = aac_sim_alloc(aac_cam_action, aac_cam_poll, "aacraidp", camsc, 306250963Sachim device_get_unit(dev), &inf->aac_sc->aac_io_lock, 1, 1, devq); 307250963Sachim if (sim == NULL) { 308250963Sachim cam_simq_free(devq); 309250963Sachim return (EIO); 310250963Sachim } 311250963Sachim 312250963Sachim /* Since every bus has it's own sim, every bus 'appears' as bus 0 */ 313250963Sachim mtx_lock(&inf->aac_sc->aac_io_lock); 314250963Sachim if (aac_xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) { 315250963Sachim cam_sim_free(sim, TRUE); 316250963Sachim mtx_unlock(&inf->aac_sc->aac_io_lock); 317250963Sachim return (EIO); 318250963Sachim } 319250963Sachim 320250963Sachim if (xpt_create_path(&path, NULL, cam_sim_path(sim), 321250963Sachim CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 322250963Sachim xpt_bus_deregister(cam_sim_path(sim)); 323250963Sachim cam_sim_free(sim, TRUE); 324250963Sachim mtx_unlock(&inf->aac_sc->aac_io_lock); 325250963Sachim return (EIO); 326250963Sachim } 327250963Sachim 328250963Sachim#if __FreeBSD_version >= 700000 329250963Sachim inf->aac_sc->cam_rescan_cb = aac_cam_rescan; 330250963Sachim#endif 331250963Sachim mtx_unlock(&inf->aac_sc->aac_io_lock); 332250963Sachim 333250963Sachim camsc->sim = sim; 334250963Sachim camsc->path = path; 335250963Sachim 336250963Sachim return (0); 337250963Sachim} 338250963Sachim 339250963Sachimstatic u_int64_t 340250963Sachimaac_eval_blockno(u_int8_t *cmdp) 341250963Sachim{ 342250963Sachim u_int64_t blockno; 343250963Sachim 344250963Sachim switch (cmdp[0]) { 345250963Sachim case READ_6: 346250963Sachim case WRITE_6: 347250963Sachim blockno = scsi_3btoul(((struct scsi_rw_6 *)cmdp)->addr); 348250963Sachim break; 349250963Sachim case READ_10: 350250963Sachim case WRITE_10: 351250963Sachim blockno = scsi_4btoul(((struct scsi_rw_10 *)cmdp)->addr); 352250963Sachim break; 353250963Sachim case READ_12: 354250963Sachim case WRITE_12: 355250963Sachim blockno = scsi_4btoul(((struct scsi_rw_12 *)cmdp)->addr); 356250963Sachim break; 357250963Sachim case READ_16: 358250963Sachim case WRITE_16: 359250963Sachim blockno = scsi_8btou64(((struct scsi_rw_16 *)cmdp)->addr); 360250963Sachim break; 361250963Sachim default: 362250963Sachim blockno = 0; 363250963Sachim break; 364250963Sachim } 365250963Sachim return(blockno); 366250963Sachim} 367250963Sachim 368250963Sachimstatic void 369250963Sachimaac_container_rw_command(struct cam_sim *sim, union ccb *ccb, u_int8_t *cmdp) 370250963Sachim{ 371250963Sachim struct aac_cam *camsc; 372250963Sachim struct aac_softc *sc; 373250963Sachim struct aac_command *cm; 374250963Sachim struct aac_fib *fib; 375250963Sachim u_int64_t blockno; 376250963Sachim 377250963Sachim camsc = (struct aac_cam *)cam_sim_softc(sim); 378250963Sachim sc = camsc->inf->aac_sc; 379250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 380250963Sachim 381250963Sachim if (aacraid_alloc_command(sc, &cm)) { 382250963Sachim struct aac_event *event; 383250963Sachim 384250963Sachim xpt_freeze_simq(sim, 1); 385250963Sachim ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 386250963Sachim ccb->ccb_h.sim_priv.entries[0].ptr = camsc; 387250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDCAM, 388250963Sachim M_NOWAIT | M_ZERO); 389250963Sachim if (event == NULL) { 390250963Sachim device_printf(sc->aac_dev, 391250963Sachim "Warning, out of memory for event\n"); 392250963Sachim return; 393250963Sachim } 394250963Sachim event->ev_callback = aac_cam_event; 395250963Sachim event->ev_arg = ccb; 396250963Sachim event->ev_type = AAC_EVENT_CMFREE; 397250963Sachim aacraid_add_event(sc, event); 398250963Sachim return; 399250963Sachim } 400250963Sachim 401250963Sachim fib = cm->cm_fib; 402250963Sachim switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 403250963Sachim case CAM_DIR_IN: 404250963Sachim cm->cm_flags |= AAC_CMD_DATAIN; 405250963Sachim break; 406250963Sachim case CAM_DIR_OUT: 407250963Sachim cm->cm_flags |= AAC_CMD_DATAOUT; 408250963Sachim break; 409250963Sachim case CAM_DIR_NONE: 410250963Sachim break; 411250963Sachim default: 412250963Sachim cm->cm_flags |= AAC_CMD_DATAIN | AAC_CMD_DATAOUT; 413250963Sachim break; 414250963Sachim } 415250963Sachim 416250963Sachim blockno = aac_eval_blockno(cmdp); 417250963Sachim 418250963Sachim cm->cm_complete = aac_container_complete; 419250963Sachim cm->cm_ccb = ccb; 420250963Sachim cm->cm_timestamp = time_uptime; 421250963Sachim cm->cm_data = (void *)ccb->csio.data_ptr; 422250963Sachim cm->cm_datalen = ccb->csio.dxfer_len; 423250963Sachim 424250963Sachim fib->Header.Size = sizeof(struct aac_fib_header); 425250963Sachim fib->Header.XferState = 426250963Sachim AAC_FIBSTATE_HOSTOWNED | 427250963Sachim AAC_FIBSTATE_INITIALISED | 428250963Sachim AAC_FIBSTATE_EMPTY | 429250963Sachim AAC_FIBSTATE_FROMHOST | 430250963Sachim AAC_FIBSTATE_REXPECTED | 431250963Sachim AAC_FIBSTATE_NORM | 432250963Sachim AAC_FIBSTATE_ASYNC | 433250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 434250963Sachim 435250963Sachim if (sc->flags & AAC_FLAGS_NEW_COMM_TYPE2) { 436250963Sachim struct aac_raw_io2 *raw; 437250963Sachim raw = (struct aac_raw_io2 *)&fib->data[0]; 438250963Sachim bzero(raw, sizeof(struct aac_raw_io2)); 439250963Sachim fib->Header.Command = RawIo2; 440250963Sachim raw->strtBlkLow = (u_int32_t)blockno; 441250963Sachim raw->strtBlkHigh = (u_int32_t)(blockno >> 32); 442250963Sachim raw->byteCnt = cm->cm_datalen; 443250963Sachim raw->ldNum = ccb->ccb_h.target_id; 444250963Sachim fib->Header.Size += sizeof(struct aac_raw_io2); 445250963Sachim cm->cm_sgtable = (struct aac_sg_table *)raw->sge; 446250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 447250963Sachim raw->flags = RIO2_IO_TYPE_READ | RIO2_SG_FORMAT_IEEE1212; 448250963Sachim else 449250963Sachim raw->flags = RIO2_IO_TYPE_WRITE | RIO2_SG_FORMAT_IEEE1212; 450250963Sachim } else if (sc->flags & AAC_FLAGS_RAW_IO) { 451250963Sachim struct aac_raw_io *raw; 452250963Sachim raw = (struct aac_raw_io *)&fib->data[0]; 453250963Sachim bzero(raw, sizeof(struct aac_raw_io)); 454250963Sachim fib->Header.Command = RawIo; 455250963Sachim raw->BlockNumber = blockno; 456250963Sachim raw->ByteCount = cm->cm_datalen; 457250963Sachim raw->ContainerId = ccb->ccb_h.target_id; 458250963Sachim fib->Header.Size += sizeof(struct aac_raw_io); 459250963Sachim cm->cm_sgtable = (struct aac_sg_table *) 460250963Sachim &raw->SgMapRaw; 461250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 462250963Sachim raw->Flags = 1; 463250963Sachim } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { 464250963Sachim fib->Header.Command = ContainerCommand; 465250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) { 466250963Sachim struct aac_blockread *br; 467250963Sachim br = (struct aac_blockread *)&fib->data[0]; 468250963Sachim br->Command = VM_CtBlockRead; 469250963Sachim br->ContainerId = ccb->ccb_h.target_id; 470250963Sachim br->BlockNumber = blockno; 471250963Sachim br->ByteCount = cm->cm_datalen; 472250963Sachim fib->Header.Size += sizeof(struct aac_blockread); 473250963Sachim cm->cm_sgtable = &br->SgMap; 474250963Sachim } else { 475250963Sachim struct aac_blockwrite *bw; 476250963Sachim bw = (struct aac_blockwrite *)&fib->data[0]; 477250963Sachim bw->Command = VM_CtBlockWrite; 478250963Sachim bw->ContainerId = ccb->ccb_h.target_id; 479250963Sachim bw->BlockNumber = blockno; 480250963Sachim bw->ByteCount = cm->cm_datalen; 481250963Sachim bw->Stable = CUNSTABLE; 482250963Sachim fib->Header.Size += sizeof(struct aac_blockwrite); 483250963Sachim cm->cm_sgtable = &bw->SgMap; 484250963Sachim } 485250963Sachim } else { 486250963Sachim fib->Header.Command = ContainerCommand64; 487250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) { 488250963Sachim struct aac_blockread64 *br; 489250963Sachim br = (struct aac_blockread64 *)&fib->data[0]; 490250963Sachim br->Command = VM_CtHostRead64; 491250963Sachim br->ContainerId = ccb->ccb_h.target_id; 492250963Sachim br->SectorCount = cm->cm_datalen/AAC_BLOCK_SIZE; 493250963Sachim br->BlockNumber = blockno; 494250963Sachim br->Pad = 0; 495250963Sachim br->Flags = 0; 496250963Sachim fib->Header.Size += sizeof(struct aac_blockread64); 497250963Sachim cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; 498250963Sachim } else { 499250963Sachim struct aac_blockwrite64 *bw; 500250963Sachim bw = (struct aac_blockwrite64 *)&fib->data[0]; 501250963Sachim bw->Command = VM_CtHostWrite64; 502250963Sachim bw->ContainerId = ccb->ccb_h.target_id; 503250963Sachim bw->SectorCount = cm->cm_datalen/AAC_BLOCK_SIZE; 504250963Sachim bw->BlockNumber = blockno; 505250963Sachim bw->Pad = 0; 506250963Sachim bw->Flags = 0; 507250963Sachim fib->Header.Size += sizeof(struct aac_blockwrite64); 508250963Sachim cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; 509250963Sachim } 510250963Sachim } 511250963Sachim aac_enqueue_ready(cm); 512250963Sachim aacraid_startio(cm->cm_sc); 513250963Sachim} 514250963Sachim 515250963Sachimstatic void 516250963Sachimaac_container_special_command(struct cam_sim *sim, union ccb *ccb, 517250963Sachim u_int8_t *cmdp) 518250963Sachim{ 519250963Sachim struct aac_cam *camsc; 520250963Sachim struct aac_softc *sc; 521250963Sachim struct aac_container *co; 522250963Sachim 523250963Sachim camsc = (struct aac_cam *)cam_sim_softc(sim); 524250963Sachim sc = camsc->inf->aac_sc; 525250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 526250963Sachim 527250963Sachim TAILQ_FOREACH(co, &sc->aac_container_tqh, co_link) { 528250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "found container %d search for %d", co->co_mntobj.ObjectId, ccb->ccb_h.target_id); 529250963Sachim if (co->co_mntobj.ObjectId == ccb->ccb_h.target_id) 530250963Sachim break; 531250963Sachim } 532250963Sachim if (co == NULL || ccb->ccb_h.target_lun != 0) { 533250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, 534250963Sachim "Container not present: cmd 0x%x id %d lun %d len %d", 535250963Sachim *cmdp, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 536250963Sachim ccb->csio.dxfer_len); 537250963Sachim ccb->ccb_h.status = CAM_DEV_NOT_THERE; 538250963Sachim xpt_done(ccb); 539250963Sachim return; 540250963Sachim } 541250963Sachim 542250963Sachim if (ccb->csio.dxfer_len) 543250963Sachim bzero(ccb->csio.data_ptr, ccb->csio.dxfer_len); 544250963Sachim 545250963Sachim switch (*cmdp) { 546250963Sachim case INQUIRY: 547250963Sachim { 548250963Sachim struct scsi_inquiry *inq = (struct scsi_inquiry *)cmdp; 549250963Sachim 550250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 551250963Sachim "Container INQUIRY id %d lun %d len %d VPD 0x%x Page 0x%x", 552250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 553250963Sachim ccb->csio.dxfer_len, inq->byte2, inq->page_code); 554250963Sachim if (!(inq->byte2 & SI_EVPD)) { 555250963Sachim struct scsi_inquiry_data *p = 556250963Sachim (struct scsi_inquiry_data *)ccb->csio.data_ptr; 557250963Sachim if (inq->page_code != 0) { 558250963Sachim aac_set_scsi_error(sc, ccb, 559250963Sachim SCSI_STATUS_CHECK_COND, 560250963Sachim SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00); 561250963Sachim xpt_done(ccb); 562250963Sachim return; 563250963Sachim } 564250963Sachim p->device = T_DIRECT; 565250963Sachim p->version = SCSI_REV_SPC2; 566250963Sachim p->response_format = 2; 567250963Sachim if (ccb->csio.dxfer_len >= 36) { 568250963Sachim p->additional_length = 31; 569250963Sachim p->flags = SID_WBus16|SID_Sync|SID_CmdQue; 570250963Sachim /* OEM Vendor defines */ 571299635Sngie strncpy(p->vendor, "Adaptec ", sizeof(p->vendor)); 572299635Sngie strncpy(p->product, "Array ", 573299635Sngie sizeof(p->product)); 574299635Sngie strncpy(p->revision, "V1.0", 575299635Sngie sizeof(p->revision)); 576250963Sachim } 577250963Sachim } else { 578250963Sachim if (inq->page_code == SVPD_SUPPORTED_PAGE_LIST) { 579250963Sachim struct scsi_vpd_supported_page_list *p = 580250963Sachim (struct scsi_vpd_supported_page_list *) 581250963Sachim ccb->csio.data_ptr; 582250963Sachim p->device = T_DIRECT; 583250963Sachim p->page_code = SVPD_SUPPORTED_PAGE_LIST; 584250963Sachim p->length = 2; 585250963Sachim p->list[0] = SVPD_SUPPORTED_PAGE_LIST; 586250963Sachim p->list[1] = SVPD_UNIT_SERIAL_NUMBER; 587250963Sachim } else if (inq->page_code == SVPD_UNIT_SERIAL_NUMBER) { 588250963Sachim struct scsi_vpd_unit_serial_number *p = 589250963Sachim (struct scsi_vpd_unit_serial_number *) 590250963Sachim ccb->csio.data_ptr; 591250963Sachim p->device = T_DIRECT; 592250963Sachim p->page_code = SVPD_UNIT_SERIAL_NUMBER; 593250963Sachim p->length = sprintf((char *)p->serial_num, 594250963Sachim "%08X%02X", co->co_uid, 595250963Sachim ccb->ccb_h.target_id); 596250963Sachim } else { 597250963Sachim aac_set_scsi_error(sc, ccb, 598250963Sachim SCSI_STATUS_CHECK_COND, 599250963Sachim SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00); 600250963Sachim xpt_done(ccb); 601250963Sachim return; 602250963Sachim } 603250963Sachim } 604250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 605250963Sachim break; 606250963Sachim } 607250963Sachim 608250963Sachim case REPORT_LUNS: 609250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 610250963Sachim "Container REPORT_LUNS id %d lun %d len %d", 611250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 612250963Sachim ccb->csio.dxfer_len); 613250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 614250963Sachim break; 615250963Sachim 616250963Sachim case START_STOP: 617250963Sachim { 618250963Sachim struct scsi_start_stop_unit *ss = 619250963Sachim (struct scsi_start_stop_unit *)cmdp; 620250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 621250963Sachim "Container START_STOP id %d lun %d len %d", 622250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 623250963Sachim ccb->csio.dxfer_len); 624250963Sachim if (sc->aac_support_opt2 & AAC_SUPPORTED_POWER_MANAGEMENT) { 625250963Sachim struct aac_command *cm; 626250963Sachim struct aac_fib *fib; 627250963Sachim struct aac_cnt_config *ccfg; 628250963Sachim 629250963Sachim if (aacraid_alloc_command(sc, &cm)) { 630250963Sachim struct aac_event *event; 631250963Sachim 632250963Sachim xpt_freeze_simq(sim, 1); 633250963Sachim ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 634250963Sachim ccb->ccb_h.sim_priv.entries[0].ptr = camsc; 635250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDCAM, 636250963Sachim M_NOWAIT | M_ZERO); 637250963Sachim if (event == NULL) { 638250963Sachim device_printf(sc->aac_dev, 639250963Sachim "Warning, out of memory for event\n"); 640250963Sachim return; 641250963Sachim } 642250963Sachim event->ev_callback = aac_cam_event; 643250963Sachim event->ev_arg = ccb; 644250963Sachim event->ev_type = AAC_EVENT_CMFREE; 645250963Sachim aacraid_add_event(sc, event); 646250963Sachim return; 647250963Sachim } 648250963Sachim 649250963Sachim fib = cm->cm_fib; 650250963Sachim cm->cm_timestamp = time_uptime; 651250963Sachim cm->cm_datalen = 0; 652250963Sachim 653250963Sachim fib->Header.Size = 654250963Sachim sizeof(struct aac_fib_header) + sizeof(struct aac_cnt_config); 655250963Sachim fib->Header.XferState = 656250963Sachim AAC_FIBSTATE_HOSTOWNED | 657250963Sachim AAC_FIBSTATE_INITIALISED | 658250963Sachim AAC_FIBSTATE_EMPTY | 659250963Sachim AAC_FIBSTATE_FROMHOST | 660250963Sachim AAC_FIBSTATE_REXPECTED | 661250963Sachim AAC_FIBSTATE_NORM | 662250963Sachim AAC_FIBSTATE_ASYNC | 663250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 664250963Sachim fib->Header.Command = ContainerCommand; 665250963Sachim 666250963Sachim /* Start unit */ 667250963Sachim ccfg = (struct aac_cnt_config *)&fib->data[0]; 668250963Sachim bzero(ccfg, sizeof (*ccfg) - CT_PACKET_SIZE); 669250963Sachim ccfg->Command = VM_ContainerConfig; 670250963Sachim ccfg->CTCommand.command = CT_PM_DRIVER_SUPPORT; 671250963Sachim ccfg->CTCommand.param[0] = (ss->how & SSS_START ? 672250963Sachim AAC_PM_DRIVERSUP_START_UNIT : 673250963Sachim AAC_PM_DRIVERSUP_STOP_UNIT); 674250963Sachim ccfg->CTCommand.param[1] = co->co_mntobj.ObjectId; 675250963Sachim ccfg->CTCommand.param[2] = 0; /* 1 - immediate */ 676250963Sachim 677250963Sachim if (aacraid_wait_command(cm) != 0 || 678250963Sachim *(u_int32_t *)&fib->data[0] != 0) { 679250963Sachim printf("Power Management: Error start/stop container %d\n", 680250963Sachim co->co_mntobj.ObjectId); 681250963Sachim } 682250963Sachim aacraid_release_command(cm); 683250963Sachim } 684250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 685250963Sachim break; 686250963Sachim } 687250963Sachim 688250963Sachim case TEST_UNIT_READY: 689250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 690250963Sachim "Container TEST_UNIT_READY id %d lun %d len %d", 691250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 692250963Sachim ccb->csio.dxfer_len); 693250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 694250963Sachim break; 695250963Sachim 696250963Sachim case REQUEST_SENSE: 697250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 698250963Sachim "Container REQUEST_SENSE id %d lun %d len %d", 699250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 700250963Sachim ccb->csio.dxfer_len); 701250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 702250963Sachim break; 703250963Sachim 704250963Sachim case READ_CAPACITY: 705250963Sachim { 706250963Sachim struct scsi_read_capacity_data *p = 707250963Sachim (struct scsi_read_capacity_data *)ccb->csio.data_ptr; 708250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 709250963Sachim "Container READ_CAPACITY id %d lun %d len %d", 710250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 711250963Sachim ccb->csio.dxfer_len); 712263024Sachim scsi_ulto4b(co->co_mntobj.ObjExtension.BlockDevice.BlockSize, p->length); 713250963Sachim /* check if greater than 2TB */ 714250963Sachim if (co->co_mntobj.CapacityHigh) { 715250963Sachim if (sc->flags & AAC_FLAGS_LBA_64BIT) 716250963Sachim scsi_ulto4b(0xffffffff, p->addr); 717250963Sachim } else { 718250963Sachim scsi_ulto4b(co->co_mntobj.Capacity-1, p->addr); 719250963Sachim } 720250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 721250963Sachim break; 722250963Sachim } 723250963Sachim 724250963Sachim case SERVICE_ACTION_IN: 725250963Sachim { 726250963Sachim struct scsi_read_capacity_data_long *p = 727250963Sachim (struct scsi_read_capacity_data_long *) 728250963Sachim ccb->csio.data_ptr; 729250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 730250963Sachim "Container SERVICE_ACTION_IN id %d lun %d len %d", 731250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 732250963Sachim ccb->csio.dxfer_len); 733250963Sachim if (((struct scsi_read_capacity_16 *)cmdp)->service_action != 734250963Sachim SRC16_SERVICE_ACTION) { 735250963Sachim aac_set_scsi_error(sc, ccb, SCSI_STATUS_CHECK_COND, 736250963Sachim SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00); 737250963Sachim xpt_done(ccb); 738250963Sachim return; 739250963Sachim } 740263024Sachim scsi_ulto4b(co->co_mntobj.ObjExtension.BlockDevice.BlockSize, p->length); 741250963Sachim scsi_ulto4b(co->co_mntobj.CapacityHigh, p->addr); 742250963Sachim scsi_ulto4b(co->co_mntobj.Capacity-1, &p->addr[4]); 743263024Sachim 744263024Sachim if (ccb->csio.dxfer_len >= 14) { 745263024Sachim u_int32_t mapping = co->co_mntobj.ObjExtension.BlockDevice.bdLgclPhysMap; 746263024Sachim p->prot_lbppbe = 0; 747263024Sachim while (mapping > 1) { 748263024Sachim mapping >>= 1; 749263024Sachim p->prot_lbppbe++; 750263024Sachim } 751263024Sachim p->prot_lbppbe &= 0x0f; 752263024Sachim } 753263024Sachim 754250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 755250963Sachim break; 756250963Sachim } 757250963Sachim 758250963Sachim case MODE_SENSE_6: 759250963Sachim { 760250963Sachim struct scsi_mode_sense_6 *msp =(struct scsi_mode_sense_6 *)cmdp; 761250963Sachim struct ms6_data { 762250963Sachim struct scsi_mode_hdr_6 hd; 763250963Sachim struct scsi_mode_block_descr bd; 764250963Sachim char pages; 765250963Sachim } *p = (struct ms6_data *)ccb->csio.data_ptr; 766250963Sachim char *pagep; 767250963Sachim int return_all_pages = FALSE; 768250963Sachim 769250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 770250963Sachim "Container MODE_SENSE id %d lun %d len %d page %d", 771250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 772250963Sachim ccb->csio.dxfer_len, msp->page); 773250963Sachim p->hd.datalen = sizeof(struct scsi_mode_hdr_6) - 1; 774250963Sachim if (co->co_mntobj.ContentState & AAC_FSCS_READONLY) 775250963Sachim p->hd.dev_specific = 0x80; /* WP */ 776250963Sachim p->hd.dev_specific |= 0x10; /* DPOFUA */ 777250963Sachim if (msp->byte2 & SMS_DBD) { 778250963Sachim p->hd.block_descr_len = 0; 779250963Sachim } else { 780250963Sachim p->hd.block_descr_len = 781250963Sachim sizeof(struct scsi_mode_block_descr); 782250963Sachim p->hd.datalen += p->hd.block_descr_len; 783263024Sachim scsi_ulto3b(co->co_mntobj.ObjExtension.BlockDevice.BlockSize, p->bd.block_len); 784250963Sachim if (co->co_mntobj.Capacity > 0xffffff || 785250963Sachim co->co_mntobj.CapacityHigh) { 786250963Sachim p->bd.num_blocks[0] = 0xff; 787250963Sachim p->bd.num_blocks[1] = 0xff; 788250963Sachim p->bd.num_blocks[2] = 0xff; 789250963Sachim } else { 790250963Sachim p->bd.num_blocks[0] = (u_int8_t) 791250963Sachim (co->co_mntobj.Capacity >> 16); 792250963Sachim p->bd.num_blocks[1] = (u_int8_t) 793250963Sachim (co->co_mntobj.Capacity >> 8); 794250963Sachim p->bd.num_blocks[2] = (u_int8_t) 795250963Sachim (co->co_mntobj.Capacity); 796250963Sachim } 797250963Sachim } 798250963Sachim pagep = &p->pages; 799250963Sachim switch (msp->page & SMS_PAGE_CODE) { 800250963Sachim case SMS_ALL_PAGES_PAGE: 801250963Sachim return_all_pages = TRUE; 802250963Sachim case SMS_CONTROL_MODE_PAGE: 803250963Sachim { 804250963Sachim struct scsi_control_page *cp = 805250963Sachim (struct scsi_control_page *)pagep; 806250963Sachim 807250963Sachim if (ccb->csio.dxfer_len <= p->hd.datalen + 8) { 808250963Sachim aac_set_scsi_error(sc, ccb, 809250963Sachim SCSI_STATUS_CHECK_COND, 810250963Sachim SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00); 811250963Sachim xpt_done(ccb); 812250963Sachim return; 813250963Sachim } 814250963Sachim cp->page_code = SMS_CONTROL_MODE_PAGE; 815250963Sachim cp->page_length = 6; 816250963Sachim p->hd.datalen += 8; 817250963Sachim pagep += 8; 818250963Sachim if (!return_all_pages) 819250963Sachim break; 820250963Sachim } 821250963Sachim case SMS_VENDOR_SPECIFIC_PAGE: 822250963Sachim break; 823250963Sachim default: 824250963Sachim aac_set_scsi_error(sc, ccb, SCSI_STATUS_CHECK_COND, 825250963Sachim SSD_KEY_ILLEGAL_REQUEST, 0x24, 0x00); 826250963Sachim xpt_done(ccb); 827250963Sachim return; 828250963Sachim } 829250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 830250963Sachim break; 831250963Sachim } 832250963Sachim 833250963Sachim case SYNCHRONIZE_CACHE: 834250963Sachim fwprintf(sc, HBA_FLAGS_DBG_COMM_B, 835250963Sachim "Container SYNCHRONIZE_CACHE id %d lun %d len %d", 836250963Sachim ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 837250963Sachim ccb->csio.dxfer_len); 838250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 839250963Sachim break; 840250963Sachim 841250963Sachim default: 842250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, 843250963Sachim "Container unsupp. cmd 0x%x id %d lun %d len %d", 844250963Sachim *cmdp, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 845250963Sachim ccb->csio.dxfer_len); 846250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; /*CAM_REQ_INVALID*/ 847250963Sachim break; 848250963Sachim } 849250963Sachim xpt_done(ccb); 850250963Sachim} 851250963Sachim 852250963Sachimstatic void 853250963Sachimaac_passthrough_command(struct cam_sim *sim, union ccb *ccb) 854250963Sachim{ 855250963Sachim struct aac_cam *camsc; 856250963Sachim struct aac_softc *sc; 857250963Sachim struct aac_command *cm; 858250963Sachim struct aac_fib *fib; 859250963Sachim struct aac_srb *srb; 860250963Sachim 861250963Sachim camsc = (struct aac_cam *)cam_sim_softc(sim); 862250963Sachim sc = camsc->inf->aac_sc; 863250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 864250963Sachim 865250963Sachim if (aacraid_alloc_command(sc, &cm)) { 866250963Sachim struct aac_event *event; 867250963Sachim 868250963Sachim xpt_freeze_simq(sim, 1); 869250963Sachim ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 870250963Sachim ccb->ccb_h.sim_priv.entries[0].ptr = camsc; 871250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDCAM, 872250963Sachim M_NOWAIT | M_ZERO); 873250963Sachim if (event == NULL) { 874250963Sachim device_printf(sc->aac_dev, 875250963Sachim "Warning, out of memory for event\n"); 876250963Sachim return; 877250963Sachim } 878250963Sachim event->ev_callback = aac_cam_event; 879250963Sachim event->ev_arg = ccb; 880250963Sachim event->ev_type = AAC_EVENT_CMFREE; 881250963Sachim aacraid_add_event(sc, event); 882250963Sachim return; 883250963Sachim } 884250963Sachim 885250963Sachim fib = cm->cm_fib; 886250963Sachim switch (ccb->ccb_h.flags & CAM_DIR_MASK) { 887250963Sachim case CAM_DIR_IN: 888250963Sachim cm->cm_flags |= AAC_CMD_DATAIN; 889250963Sachim break; 890250963Sachim case CAM_DIR_OUT: 891250963Sachim cm->cm_flags |= AAC_CMD_DATAOUT; 892250963Sachim break; 893250963Sachim case CAM_DIR_NONE: 894250963Sachim break; 895250963Sachim default: 896250963Sachim cm->cm_flags |= AAC_CMD_DATAIN | AAC_CMD_DATAOUT; 897250963Sachim break; 898250963Sachim } 899250963Sachim 900250963Sachim srb = (struct aac_srb *)&fib->data[0]; 901250963Sachim srb->function = AAC_SRB_FUNC_EXECUTE_SCSI; 902250963Sachim if (cm->cm_flags & (AAC_CMD_DATAIN|AAC_CMD_DATAOUT)) 903250963Sachim srb->flags = AAC_SRB_FLAGS_UNSPECIFIED_DIRECTION; 904250963Sachim if (cm->cm_flags & AAC_CMD_DATAIN) 905250963Sachim srb->flags = AAC_SRB_FLAGS_DATA_IN; 906250963Sachim else if (cm->cm_flags & AAC_CMD_DATAOUT) 907250963Sachim srb->flags = AAC_SRB_FLAGS_DATA_OUT; 908250963Sachim else 909250963Sachim srb->flags = AAC_SRB_FLAGS_NO_DATA_XFER; 910250963Sachim 911250963Sachim /* 912250963Sachim * Copy the CDB into the SRB. It's only 6-16 bytes, 913250963Sachim * so a copy is not too expensive. 914250963Sachim */ 915250963Sachim srb->cdb_len = ccb->csio.cdb_len; 916250963Sachim if (ccb->ccb_h.flags & CAM_CDB_POINTER) 917250963Sachim bcopy(ccb->csio.cdb_io.cdb_ptr, (u_int8_t *)&srb->cdb[0], 918250963Sachim srb->cdb_len); 919250963Sachim else 920250963Sachim bcopy(ccb->csio.cdb_io.cdb_bytes, (u_int8_t *)&srb->cdb[0], 921250963Sachim srb->cdb_len); 922250963Sachim 923250963Sachim /* Set command */ 924250963Sachim fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) ? 925250963Sachim ScsiPortCommandU64 : ScsiPortCommand; 926250963Sachim fib->Header.Size = sizeof(struct aac_fib_header) + 927250963Sachim sizeof(struct aac_srb); 928250963Sachim 929250963Sachim /* Map the s/g list */ 930250963Sachim cm->cm_sgtable = &srb->sg_map; 931250963Sachim if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { 932250963Sachim /* 933250963Sachim * Arrange things so that the S/G 934250963Sachim * map will get set up automagically 935250963Sachim */ 936250963Sachim cm->cm_data = (void *)ccb->csio.data_ptr; 937250963Sachim cm->cm_datalen = ccb->csio.dxfer_len; 938250963Sachim srb->data_len = ccb->csio.dxfer_len; 939250963Sachim } else { 940250963Sachim cm->cm_data = NULL; 941250963Sachim cm->cm_datalen = 0; 942250963Sachim srb->data_len = 0; 943250963Sachim } 944250963Sachim 945250963Sachim srb->bus = camsc->inf->BusNumber - 1; /* Bus no. rel. to the card */ 946250963Sachim srb->target = ccb->ccb_h.target_id; 947250963Sachim srb->lun = ccb->ccb_h.target_lun; 948250963Sachim srb->timeout = ccb->ccb_h.timeout; /* XXX */ 949250963Sachim srb->retry_limit = 0; 950250963Sachim 951250963Sachim cm->cm_complete = aac_cam_complete; 952250963Sachim cm->cm_ccb = ccb; 953250963Sachim cm->cm_timestamp = time_uptime; 954250963Sachim 955250963Sachim fib->Header.XferState = 956250963Sachim AAC_FIBSTATE_HOSTOWNED | 957250963Sachim AAC_FIBSTATE_INITIALISED | 958250963Sachim AAC_FIBSTATE_FROMHOST | 959250963Sachim AAC_FIBSTATE_REXPECTED | 960250963Sachim AAC_FIBSTATE_NORM | 961250963Sachim AAC_FIBSTATE_ASYNC | 962250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 963250963Sachim 964250963Sachim aac_enqueue_ready(cm); 965250963Sachim aacraid_startio(cm->cm_sc); 966250963Sachim} 967250963Sachim 968250963Sachimstatic void 969250963Sachimaac_cam_action(struct cam_sim *sim, union ccb *ccb) 970250963Sachim{ 971250963Sachim struct aac_cam *camsc; 972250963Sachim struct aac_softc *sc; 973250963Sachim 974250963Sachim camsc = (struct aac_cam *)cam_sim_softc(sim); 975250963Sachim sc = camsc->inf->aac_sc; 976250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 977250963Sachim mtx_assert(&sc->aac_io_lock, MA_OWNED); 978250963Sachim 979250963Sachim /* Synchronous ops, and ops that don't require communication with the 980250963Sachim * controller */ 981250963Sachim switch(ccb->ccb_h.func_code) { 982250963Sachim case XPT_SCSI_IO: 983250963Sachim /* This is handled down below */ 984250963Sachim break; 985250963Sachim case XPT_CALC_GEOMETRY: 986250963Sachim { 987250963Sachim struct ccb_calc_geometry *ccg; 988250963Sachim u_int32_t size_mb; 989250963Sachim u_int32_t secs_per_cylinder; 990250963Sachim 991250963Sachim ccg = &ccb->ccg; 992250963Sachim size_mb = ccg->volume_size / 993250963Sachim ((1024L * 1024L) / ccg->block_size); 994250963Sachim if (size_mb >= (2 * 1024)) { /* 2GB */ 995250963Sachim ccg->heads = 255; 996250963Sachim ccg->secs_per_track = 63; 997250963Sachim } else if (size_mb >= (1 * 1024)) { /* 1GB */ 998250963Sachim ccg->heads = 128; 999250963Sachim ccg->secs_per_track = 32; 1000250963Sachim } else { 1001250963Sachim ccg->heads = 64; 1002250963Sachim ccg->secs_per_track = 32; 1003250963Sachim } 1004250963Sachim secs_per_cylinder = ccg->heads * ccg->secs_per_track; 1005250963Sachim ccg->cylinders = ccg->volume_size / secs_per_cylinder; 1006250963Sachim 1007250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 1008250963Sachim xpt_done(ccb); 1009250963Sachim return; 1010250963Sachim } 1011250963Sachim case XPT_PATH_INQ: 1012250963Sachim { 1013250963Sachim struct ccb_pathinq *cpi = &ccb->cpi; 1014250963Sachim 1015250963Sachim cpi->version_num = 1; 1016250963Sachim cpi->target_sprt = 0; 1017250963Sachim cpi->hba_eng_cnt = 0; 1018250963Sachim cpi->max_target = camsc->inf->TargetsPerBus; 1019250963Sachim cpi->max_lun = 8; /* Per the controller spec */ 1020250963Sachim cpi->initiator_id = camsc->inf->InitiatorBusId; 1021250963Sachim cpi->bus_id = camsc->inf->BusNumber; 1022250963Sachim#if __FreeBSD_version >= 800000 1023250963Sachim cpi->maxio = sc->aac_max_sectors << 9; 1024250963Sachim#endif 1025250963Sachim 1026250963Sachim /* 1027250963Sachim * Resetting via the passthrough or parallel bus scan 1028250963Sachim * causes problems. 1029250963Sachim */ 1030250963Sachim cpi->hba_misc = PIM_NOBUSRESET; 1031250963Sachim cpi->hba_inquiry = PI_TAG_ABLE; 1032250963Sachim cpi->base_transfer_speed = 300000; 1033250963Sachim#ifdef CAM_NEW_TRAN_CODE 1034250963Sachim cpi->hba_misc |= PIM_SEQSCAN; 1035250963Sachim cpi->protocol = PROTO_SCSI; 1036250963Sachim cpi->transport = XPORT_SAS; 1037250963Sachim cpi->transport_version = 0; 1038250963Sachim cpi->protocol_version = SCSI_REV_SPC2; 1039250963Sachim#endif 1040315813Smav strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1041315813Smav strlcpy(cpi->hba_vid, "PMC-Sierra", HBA_IDLEN); 1042315813Smav strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1043250963Sachim cpi->unit_number = cam_sim_unit(sim); 1044250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 1045250963Sachim xpt_done(ccb); 1046250963Sachim return; 1047250963Sachim } 1048250963Sachim case XPT_GET_TRAN_SETTINGS: 1049250963Sachim { 1050250963Sachim#ifdef CAM_NEW_TRAN_CODE 1051250963Sachim struct ccb_trans_settings_scsi *scsi = 1052250963Sachim &ccb->cts.proto_specific.scsi; 1053250963Sachim struct ccb_trans_settings_spi *spi = 1054250963Sachim &ccb->cts.xport_specific.spi; 1055250963Sachim ccb->cts.protocol = PROTO_SCSI; 1056250963Sachim ccb->cts.protocol_version = SCSI_REV_SPC2; 1057250963Sachim ccb->cts.transport = XPORT_SAS; 1058250963Sachim ccb->cts.transport_version = 0; 1059250963Sachim scsi->valid = CTS_SCSI_VALID_TQ; 1060250963Sachim scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 1061250963Sachim spi->valid |= CTS_SPI_VALID_DISC; 1062250963Sachim spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 1063250963Sachim#else 1064250963Sachim ccb->cts.flags = ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); 1065250963Sachim ccb->cts.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 1066250963Sachim#endif 1067250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 1068250963Sachim xpt_done(ccb); 1069250963Sachim return; 1070250963Sachim } 1071250963Sachim case XPT_SET_TRAN_SETTINGS: 1072250963Sachim ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1073250963Sachim xpt_done(ccb); 1074250963Sachim return; 1075250963Sachim case XPT_RESET_BUS: 1076250963Sachim if (!(sc->flags & AAC_FLAGS_CAM_NORESET) && 1077250963Sachim camsc->inf->BusType != CONTAINER_BUS) { 1078250963Sachim ccb->ccb_h.status = aac_cam_reset_bus(sim, ccb); 1079250963Sachim } else { 1080250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 1081250963Sachim } 1082250963Sachim xpt_done(ccb); 1083250963Sachim return; 1084250963Sachim case XPT_RESET_DEV: 1085250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 1086250963Sachim xpt_done(ccb); 1087250963Sachim return; 1088250963Sachim case XPT_ABORT: 1089250963Sachim ccb->ccb_h.status = aac_cam_abort_ccb(sim, ccb); 1090250963Sachim xpt_done(ccb); 1091250963Sachim return; 1092250963Sachim case XPT_TERM_IO: 1093250963Sachim ccb->ccb_h.status = aac_cam_term_io(sim, ccb); 1094250963Sachim xpt_done(ccb); 1095250963Sachim return; 1096250963Sachim default: 1097250963Sachim device_printf(sc->aac_dev, "Unsupported command 0x%x\n", 1098250963Sachim ccb->ccb_h.func_code); 1099250963Sachim ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1100250963Sachim xpt_done(ccb); 1101250963Sachim return; 1102250963Sachim } 1103250963Sachim 1104250963Sachim /* Async ops that require communcation with the controller */ 1105250963Sachim if (camsc->inf->BusType == CONTAINER_BUS) { 1106250963Sachim u_int8_t *cmdp; 1107250963Sachim 1108250963Sachim if (ccb->ccb_h.flags & CAM_CDB_POINTER) 1109250963Sachim cmdp = ccb->csio.cdb_io.cdb_ptr; 1110250963Sachim else 1111250963Sachim cmdp = &ccb->csio.cdb_io.cdb_bytes[0]; 1112250963Sachim 1113250963Sachim if (*cmdp==READ_6 || *cmdp==WRITE_6 || *cmdp==READ_10 || 1114250963Sachim *cmdp==WRITE_10 || *cmdp==READ_12 || *cmdp==WRITE_12 || 1115250963Sachim *cmdp==READ_16 || *cmdp==WRITE_16) 1116250963Sachim aac_container_rw_command(sim, ccb, cmdp); 1117250963Sachim else 1118250963Sachim aac_container_special_command(sim, ccb, cmdp); 1119250963Sachim } else { 1120250963Sachim aac_passthrough_command(sim, ccb); 1121250963Sachim } 1122250963Sachim} 1123250963Sachim 1124250963Sachimstatic void 1125250963Sachimaac_cam_poll(struct cam_sim *sim) 1126250963Sachim{ 1127250963Sachim /* 1128250963Sachim * Pinging the interrupt routine isn't very safe, nor is it 1129250963Sachim * really necessary. Do nothing. 1130250963Sachim */ 1131250963Sachim} 1132250963Sachim 1133250963Sachimstatic void 1134250963Sachimaac_container_complete(struct aac_command *cm) 1135250963Sachim{ 1136250963Sachim union ccb *ccb; 1137250963Sachim u_int32_t status; 1138250963Sachim 1139316846Savg fwprintf(cm->cm_sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1140250963Sachim ccb = cm->cm_ccb; 1141250963Sachim status = ((u_int32_t *)cm->cm_fib->data)[0]; 1142250963Sachim 1143250963Sachim if (cm->cm_flags & AAC_CMD_RESET) { 1144250963Sachim ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 1145315854Savg } else if (status == ST_OK) { 1146250963Sachim ccb->ccb_h.status = CAM_REQ_CMP; 1147250963Sachim } else if (status == ST_NOT_READY) { 1148250963Sachim ccb->ccb_h.status = CAM_BUSY; 1149250963Sachim } else { 1150250963Sachim ccb->ccb_h.status = CAM_REQ_CMP_ERR; 1151250963Sachim } 1152250963Sachim 1153250963Sachim aacraid_release_command(cm); 1154250963Sachim xpt_done(ccb); 1155250963Sachim} 1156250963Sachim 1157250963Sachimstatic void 1158250963Sachimaac_cam_complete(struct aac_command *cm) 1159250963Sachim{ 1160250963Sachim union ccb *ccb; 1161250963Sachim struct aac_srb_response *srbr; 1162250963Sachim struct aac_softc *sc; 1163250963Sachim 1164250963Sachim sc = cm->cm_sc; 1165250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1166250963Sachim ccb = cm->cm_ccb; 1167250963Sachim srbr = (struct aac_srb_response *)&cm->cm_fib->data[0]; 1168250963Sachim 1169250963Sachim if (cm->cm_flags & AAC_CMD_FASTRESP) { 1170250963Sachim /* fast response */ 1171250963Sachim srbr->srb_status = CAM_REQ_CMP; 1172250963Sachim srbr->scsi_status = SCSI_STATUS_OK; 1173250963Sachim srbr->sense_len = 0; 1174250963Sachim } 1175250963Sachim 1176250963Sachim if (cm->cm_flags & AAC_CMD_RESET) { 1177250963Sachim ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 1178250963Sachim } else if (srbr->fib_status != 0) { 1179250963Sachim device_printf(sc->aac_dev, "Passthru FIB failed!\n"); 1180250963Sachim ccb->ccb_h.status = CAM_REQ_ABORTED; 1181250963Sachim } else { 1182250963Sachim /* 1183250963Sachim * The SRB error codes just happen to match the CAM error 1184250963Sachim * codes. How convienient! 1185250963Sachim */ 1186250963Sachim ccb->ccb_h.status = srbr->srb_status; 1187250963Sachim 1188250963Sachim /* Take care of SCSI_IO ops. */ 1189250963Sachim if (ccb->ccb_h.func_code == XPT_SCSI_IO) { 1190250963Sachim u_int8_t command, device; 1191250963Sachim 1192250963Sachim ccb->csio.scsi_status = srbr->scsi_status; 1193250963Sachim 1194250963Sachim /* Take care of autosense */ 1195250963Sachim if (srbr->sense_len) { 1196250963Sachim int sense_len, scsi_sense_len; 1197250963Sachim 1198250963Sachim scsi_sense_len = sizeof(struct scsi_sense_data); 1199250963Sachim bzero(&ccb->csio.sense_data, scsi_sense_len); 1200250963Sachim sense_len = (srbr->sense_len > 1201250963Sachim scsi_sense_len) ? scsi_sense_len : 1202250963Sachim srbr->sense_len; 1203250963Sachim bcopy(&srbr->sense[0], &ccb->csio.sense_data, 1204250963Sachim srbr->sense_len); 1205250963Sachim ccb->csio.sense_len = sense_len; 1206250963Sachim ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 1207250963Sachim // scsi_sense_print(&ccb->csio); 1208250963Sachim } 1209250963Sachim 1210250963Sachim /* If this is an inquiry command, fake things out */ 1211250963Sachim if (ccb->ccb_h.flags & CAM_CDB_POINTER) 1212250963Sachim command = ccb->csio.cdb_io.cdb_ptr[0]; 1213250963Sachim else 1214250963Sachim command = ccb->csio.cdb_io.cdb_bytes[0]; 1215250963Sachim 1216250963Sachim if (command == INQUIRY) { 1217250963Sachim if (ccb->ccb_h.status == CAM_REQ_CMP) { 1218250963Sachim device = ccb->csio.data_ptr[0] & 0x1f; 1219250963Sachim /* 1220250963Sachim * We want DASD and PROC devices to only be 1221250963Sachim * visible through the pass device. 1222250963Sachim */ 1223250963Sachim if ((device == T_DIRECT && 1224250963Sachim !(sc->aac_feature_bits & AAC_SUPPL_SUPPORTED_JBOD)) || 1225263024Sachim (device == T_PROCESSOR)) 1226250963Sachim ccb->csio.data_ptr[0] = 1227250963Sachim ((device & 0xe0) | T_NODEVICE); 1228250963Sachim 1229263024Sachim /* handle phys. components of a log. drive */ 1230263024Sachim if (ccb->csio.data_ptr[0] & 0x20) { 1231263024Sachim if (sc->hint_flags & 8) { 1232263024Sachim /* expose phys. device (daXX) */ 1233263024Sachim ccb->csio.data_ptr[0] &= 0xdf; 1234263024Sachim } else { 1235263024Sachim /* phys. device only visible through pass device (passXX) */ 1236263024Sachim ccb->csio.data_ptr[0] |= 0x10; 1237263024Sachim } 1238263024Sachim } 1239250963Sachim } else if (ccb->ccb_h.status == CAM_SEL_TIMEOUT && 1240250963Sachim ccb->ccb_h.target_lun != 0) { 1241250963Sachim /* fix for INQUIRYs on Lun>0 */ 1242250963Sachim ccb->ccb_h.status = CAM_DEV_NOT_THERE; 1243250963Sachim } 1244250963Sachim } 1245250963Sachim } 1246250963Sachim } 1247250963Sachim 1248250963Sachim aacraid_release_command(cm); 1249250963Sachim xpt_done(ccb); 1250250963Sachim} 1251250963Sachim 1252250963Sachimstatic u_int32_t 1253250963Sachimaac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb) 1254250963Sachim{ 1255250963Sachim struct aac_command *cm; 1256250963Sachim struct aac_fib *fib; 1257250963Sachim struct aac_softc *sc; 1258250963Sachim struct aac_cam *camsc; 1259250963Sachim struct aac_vmioctl *vmi; 1260250963Sachim struct aac_resetbus *rbc; 1261250963Sachim u_int32_t rval; 1262250963Sachim 1263250963Sachim camsc = (struct aac_cam *)cam_sim_softc(sim); 1264250963Sachim sc = camsc->inf->aac_sc; 1265250963Sachim 1266250963Sachim if (sc == NULL) { 1267250963Sachim printf("aac: Null sc?\n"); 1268250963Sachim return (CAM_REQ_ABORTED); 1269250963Sachim } 1270250963Sachim 1271250963Sachim if (aacraid_alloc_command(sc, &cm)) { 1272250963Sachim struct aac_event *event; 1273250963Sachim 1274250963Sachim xpt_freeze_simq(sim, 1); 1275250963Sachim ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 1276250963Sachim ccb->ccb_h.sim_priv.entries[0].ptr = camsc; 1277250963Sachim event = malloc(sizeof(struct aac_event), M_AACRAIDCAM, 1278250963Sachim M_NOWAIT | M_ZERO); 1279250963Sachim if (event == NULL) { 1280250963Sachim device_printf(sc->aac_dev, 1281250963Sachim "Warning, out of memory for event\n"); 1282250963Sachim return (CAM_REQ_ABORTED); 1283250963Sachim } 1284250963Sachim event->ev_callback = aac_cam_event; 1285250963Sachim event->ev_arg = ccb; 1286250963Sachim event->ev_type = AAC_EVENT_CMFREE; 1287250963Sachim aacraid_add_event(sc, event); 1288250963Sachim return (CAM_REQ_ABORTED); 1289250963Sachim } 1290250963Sachim 1291250963Sachim fib = cm->cm_fib; 1292250963Sachim cm->cm_timestamp = time_uptime; 1293250963Sachim cm->cm_datalen = 0; 1294250963Sachim 1295250963Sachim fib->Header.Size = 1296250963Sachim sizeof(struct aac_fib_header) + sizeof(struct aac_vmioctl); 1297250963Sachim fib->Header.XferState = 1298250963Sachim AAC_FIBSTATE_HOSTOWNED | 1299250963Sachim AAC_FIBSTATE_INITIALISED | 1300250963Sachim AAC_FIBSTATE_EMPTY | 1301250963Sachim AAC_FIBSTATE_FROMHOST | 1302250963Sachim AAC_FIBSTATE_REXPECTED | 1303250963Sachim AAC_FIBSTATE_NORM | 1304250963Sachim AAC_FIBSTATE_ASYNC | 1305250963Sachim AAC_FIBSTATE_FAST_RESPONSE; 1306250963Sachim fib->Header.Command = ContainerCommand; 1307250963Sachim 1308250963Sachim vmi = (struct aac_vmioctl *)&fib->data[0]; 1309250963Sachim bzero(vmi, sizeof(struct aac_vmioctl)); 1310250963Sachim 1311250963Sachim vmi->Command = VM_Ioctl; 1312250963Sachim vmi->ObjType = FT_DRIVE; 1313250963Sachim vmi->MethId = sc->scsi_method_id; 1314250963Sachim vmi->ObjId = 0; 1315250963Sachim vmi->IoctlCmd = ResetBus; 1316250963Sachim 1317250963Sachim rbc = (struct aac_resetbus *)&vmi->IoctlBuf[0]; 1318250963Sachim rbc->BusNumber = camsc->inf->BusNumber - 1; 1319250963Sachim 1320250963Sachim if (aacraid_wait_command(cm) != 0) { 1321250963Sachim device_printf(sc->aac_dev,"Error sending ResetBus command\n"); 1322250963Sachim rval = CAM_REQ_ABORTED; 1323250963Sachim } else { 1324250963Sachim rval = CAM_REQ_CMP; 1325250963Sachim } 1326250963Sachim aacraid_release_command(cm); 1327250963Sachim return (rval); 1328250963Sachim} 1329250963Sachim 1330250963Sachimstatic u_int32_t 1331250963Sachimaac_cam_abort_ccb(struct cam_sim *sim, union ccb *ccb) 1332250963Sachim{ 1333250963Sachim return (CAM_UA_ABORT); 1334250963Sachim} 1335250963Sachim 1336250963Sachimstatic u_int32_t 1337250963Sachimaac_cam_term_io(struct cam_sim *sim, union ccb *ccb) 1338250963Sachim{ 1339250963Sachim return (CAM_UA_TERMIO); 1340250963Sachim} 1341250963Sachim 1342250963Sachimstatic int 1343250963Sachimaac_load_map_command_sg(struct aac_softc *sc, struct aac_command *cm) 1344250963Sachim{ 1345250963Sachim int error; 1346250963Sachim 1347250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1348250963Sachim error = bus_dmamap_load(sc->aac_buffer_dmat, 1349250963Sachim cm->cm_datamap, cm->cm_data, cm->cm_datalen, 1350250963Sachim aacraid_map_command_sg, cm, 0); 1351250963Sachim if (error == EINPROGRESS) { 1352250963Sachim fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "freezing queue\n"); 1353250963Sachim sc->flags |= AAC_QUEUE_FRZN; 1354250963Sachim error = 0; 1355250963Sachim } else if (error != 0) { 1356250963Sachim panic("aac_load_map_command_sg: unexpected error %d from " 1357250963Sachim "busdma", error); 1358250963Sachim } 1359250963Sachim return(error); 1360250963Sachim} 1361250963Sachim 1362250963Sachim/* 1363250963Sachim * Start as much queued I/O as possible on the controller 1364250963Sachim */ 1365250963Sachimvoid 1366250963Sachimaacraid_startio(struct aac_softc *sc) 1367250963Sachim{ 1368250963Sachim struct aac_command *cm; 1369250963Sachim 1370250963Sachim fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); 1371250963Sachim 1372250963Sachim for (;;) { 1373250963Sachim if (sc->aac_state & AAC_STATE_RESET) { 1374250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "AAC_STATE_RESET"); 1375250963Sachim break; 1376250963Sachim } 1377250963Sachim /* 1378250963Sachim * This flag might be set if the card is out of resources. 1379250963Sachim * Checking it here prevents an infinite loop of deferrals. 1380250963Sachim */ 1381250963Sachim if (sc->flags & AAC_QUEUE_FRZN) { 1382250963Sachim fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "AAC_QUEUE_FRZN"); 1383250963Sachim break; 1384250963Sachim } 1385250963Sachim 1386250963Sachim /* 1387250963Sachim * Try to get a command that's been put off for lack of 1388250963Sachim * resources 1389250963Sachim */ 1390250963Sachim if (sc->flags & AAC_FLAGS_SYNC_MODE) { 1391250963Sachim /* sync. transfer mode */ 1392250963Sachim if (sc->aac_sync_cm) 1393250963Sachim break; 1394250963Sachim cm = aac_dequeue_ready(sc); 1395250963Sachim sc->aac_sync_cm = cm; 1396250963Sachim } else { 1397250963Sachim cm = aac_dequeue_ready(sc); 1398250963Sachim } 1399250963Sachim 1400250963Sachim /* nothing to do? */ 1401250963Sachim if (cm == NULL) 1402250963Sachim break; 1403250963Sachim 1404250963Sachim /* don't map more than once */ 1405250963Sachim if (cm->cm_flags & AAC_CMD_MAPPED) 1406250963Sachim panic("aac: command %p already mapped", cm); 1407250963Sachim 1408250963Sachim /* 1409250963Sachim * Set up the command to go to the controller. If there are no 1410250963Sachim * data buffers associated with the command then it can bypass 1411250963Sachim * busdma. 1412250963Sachim */ 1413250963Sachim if (cm->cm_datalen) 1414250963Sachim aac_load_map_command_sg(sc, cm); 1415250963Sachim else 1416250963Sachim aacraid_map_command_sg(cm, NULL, 0, 0); 1417250963Sachim } 1418250963Sachim} 1419