Print this page
NEX-1889 upstream

*** 22,31 **** --- 22,32 ---- /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved. + * Copyright (c) 2014, Tegile Systems Inc. All rights reserved. */ /* * Copyright (c) 2000 to 2010, LSI Corporation. * All rights reserved.
*** 243,253 **** static void mptsas_cmd_timeout(mptsas_t *mpt, mptsas_target_t *ptgt); static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd); static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint32_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode); static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl); static uint8_t mptsas_get_fw_diag_buffer_number(mptsas_t *mpt, uint32_t unique_id); --- 244,254 ---- static void mptsas_cmd_timeout(mptsas_t *mpt, mptsas_target_t *ptgt); static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd); static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint8_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode); static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl); static uint8_t mptsas_get_fw_diag_buffer_number(mptsas_t *mpt, uint32_t unique_id);
*** 489,499 **** 1, /* minxfer - gran. of DMA engine */ 0x00ffffffull, /* maxxfer - gran. of DMA engine */ 0xffffffffull, /* max segment size (DMA boundary) */ MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length */ 512, /* granularity - device transfer size */ ! DDI_DMA_RELAXED_ORDERING /* flags, enable relaxed ordering */ }; ddi_device_acc_attr_t mptsas_dev_attr = { DDI_DEVICE_ATTR_V1, DDI_STRUCTURE_LE_ACC, --- 490,500 ---- 1, /* minxfer - gran. of DMA engine */ 0x00ffffffull, /* maxxfer - gran. of DMA engine */ 0xffffffffull, /* max segment size (DMA boundary) */ MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length */ 512, /* granularity - device transfer size */ ! 0 /* flags, set to 0 */ }; ddi_device_acc_attr_t mptsas_dev_attr = { DDI_DEVICE_ATTR_V1, DDI_STRUCTURE_LE_ACC,
*** 567,577 **** /* * Local static data */ #if defined(MPTSAS_DEBUG) ! uint32_t mptsas_debug_flags = 0; #endif /* defined(MPTSAS_DEBUG) */ uint32_t mptsas_debug_resets = 0; static kmutex_t mptsas_global_mutex; static void *mptsas_state; /* soft state ptr */ --- 568,578 ---- /* * Local static data */ #if defined(MPTSAS_DEBUG) ! uint32_t mptsas_debug_flags = 0x0; #endif /* defined(MPTSAS_DEBUG) */ uint32_t mptsas_debug_resets = 0; static kmutex_t mptsas_global_mutex; static void *mptsas_state; /* soft state ptr */
*** 585,595 **** --- 586,610 ---- static clock_t mptsas_scsi_watchdog_tick; static clock_t mptsas_tick; static timeout_id_t mptsas_reset_watch; static timeout_id_t mptsas_timeout_id; static int mptsas_timeouts_enabled = 0; + /* + * The only software retriction on switching msg buffers to 64 bit seems to + * be the Auto Request Sense interface. The high 32 bits for all such + * requests appear to be required to sit in the same 4G segment. + * See initialization of SenseBufferAddressHigh in mptsas_init.c, and + * the use of SenseBufferLowAddress in requests. Note that there is + * currently a dependency on scsi_alloc_consistent_buf() adhering to + * this requirement. + * There is also a question about improved performance over PCI/PCIX + * if transfers are within the first 4Gb. + */ + static int mptsas_use_64bit_msgaddr = 0; + + /* * warlock directives */ _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt \ mptsas_cmd NcrTableIndirect buf scsi_cdb scsi_status)) _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", smp_pkt))
*** 1163,1173 **** --- 1178,1192 ---- mpt->m_dip = dip; mpt->m_instance = instance; /* Make a per-instance copy of the structures */ mpt->m_io_dma_attr = mptsas_dma_attrs64; + if (mptsas_use_64bit_msgaddr) { + mpt->m_msg_dma_attr = mptsas_dma_attrs64; + } else { mpt->m_msg_dma_attr = mptsas_dma_attrs; + } mpt->m_reg_acc_attr = mptsas_dev_attr; mpt->m_dev_acc_attr = mptsas_dev_attr; /* * Initialize FMA
*** 1259,1268 **** --- 1278,1296 ---- } mutex_exit(&mpt->m_doneq_mutex); doneq_thread_create++; } + /* + * Disable hardware interrupt since we're not ready to + * handle it yet. + */ + MPTSAS_DISABLE_INTR(mpt); + if (mptsas_register_intrs(mpt) == FALSE) + goto fail; + intr_added++; + /* Initialize mutex used in interrupt handler */ mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(mpt->m_intr_pri)); mutex_init(&mpt->m_passthru_mutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&mpt->m_tx_waitq_mutex, NULL, MUTEX_DRIVER,
*** 1278,1296 **** cv_init(&mpt->m_fw_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_config_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_fw_diag_cv, NULL, CV_DRIVER, NULL); mutex_init_done++; - /* - * Disable hardware interrupt since we're not ready to - * handle it yet. - */ - MPTSAS_DISABLE_INTR(mpt); - if (mptsas_register_intrs(mpt) == FALSE) - goto fail; - intr_added++; - mutex_enter(&mpt->m_mutex); /* * Initialize power management component */ if (mpt->m_options & MPTSAS_OPT_PM) { --- 1306,1315 ----
*** 2220,2230 **** /* * create kmem cache for packets */ (void) sprintf(buf, "mptsas%d_cache", instance); mpt->m_kmem_cache = kmem_cache_create(buf, ! sizeof (struct mptsas_cmd) + scsi_pkt_size(), 8, mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_kmem_cache == NULL) { mptsas_log(mpt, CE_WARN, "creating kmem cache failed"); --- 2239,2249 ---- /* * create kmem cache for packets */ (void) sprintf(buf, "mptsas%d_cache", instance); mpt->m_kmem_cache = kmem_cache_create(buf, ! sizeof (struct mptsas_cmd) + scsi_pkt_size(), 16, mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_kmem_cache == NULL) { mptsas_log(mpt, CE_WARN, "creating kmem cache failed");
*** 2235,2245 **** * create kmem cache for extra SGL frames if SGL cannot * be accomodated into main request frame. */ (void) sprintf(buf, "mptsas%d_cache_frames", instance); mpt->m_cache_frames = kmem_cache_create(buf, ! sizeof (mptsas_cache_frames_t), 8, mptsas_cache_frames_constructor, mptsas_cache_frames_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_cache_frames == NULL) { mptsas_log(mpt, CE_WARN, "creating cache for frames failed"); --- 2254,2264 ---- * create kmem cache for extra SGL frames if SGL cannot * be accomodated into main request frame. */ (void) sprintf(buf, "mptsas%d_cache_frames", instance); mpt->m_cache_frames = kmem_cache_create(buf, ! sizeof (mptsas_cache_frames_t), 16, mptsas_cache_frames_constructor, mptsas_cache_frames_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_cache_frames == NULL) { mptsas_log(mpt, CE_WARN, "creating cache for frames failed");
*** 3969,3979 **** /* * Store the SGL memory address. This chip uses this * address to dma to and from the driver. The second * address is the address mpt uses to fill in the SGL. */ ! p->m_phys_addr = cookie.dmac_address; return (DDI_SUCCESS); } static void --- 3988,3998 ---- /* * Store the SGL memory address. This chip uses this * address to dma to and from the driver. The second * address is the address mpt uses to fill in the SGL. */ ! p->m_phys_addr = cookie.dmac_laddress; return (DDI_SUCCESS); } static void
*** 4176,4233 **** } (*pkt->pkt_comp)(pkt); } static void ! mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control, ! pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) { ! uint_t cookiec; mptti_t *dmap; uint32_t flags; - pMpi2SGESimple64_t sge; - pMpi2SGEChain64_t sgechain; - ASSERT(cmd->cmd_flags & CFLAG_DMAVALID); - /* - * Save the number of entries in the DMA - * Scatter/Gather list - */ - cookiec = cmd->cmd_cookiec; - - NDBG1(("mptsas_sge_setup: cookiec=%d", cookiec)); - - /* - * Set read/write bit in control. - */ - if (cmd->cmd_flags & CFLAG_DMASEND) { - *control |= MPI2_SCSIIO_CONTROL_WRITE; - } else { - *control |= MPI2_SCSIIO_CONTROL_READ; - } - - ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount); - - /* - * We have 2 cases here. First where we can fit all the - * SG elements into the main frame, and the case - * where we can't. - * If we have more cookies than we can attach to a frame - * we will need to use a chain element to point - * a location of memory where the rest of the S/G - * elements reside. - */ - if (cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) { dmap = cmd->cmd_sg; sge = (pMpi2SGESimple64_t)(&frame->SGL); while (cookiec--) { ! ddi_put32(acc_hdl, ! &sge->Address.Low, dmap->addr.address64.Low); ! ddi_put32(acc_hdl, ! &sge->Address.High, dmap->addr.address64.High); ! ddi_put32(acc_hdl, &sge->FlagsLength, ! dmap->count); flags = ddi_get32(acc_hdl, &sge->FlagsLength); flags |= ((uint32_t) (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << --- 4195,4221 ---- } (*pkt->pkt_comp)(pkt); } static void ! mptsas_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame, ! ddi_acc_handle_t acc_hdl, uint_t cookiec, ! uint32_t end_flags) { ! pMpi2SGESimple64_t sge; mptti_t *dmap; uint32_t flags; dmap = cmd->cmd_sg; + sge = (pMpi2SGESimple64_t)(&frame->SGL); while (cookiec--) { ! ddi_put32(acc_hdl, &sge->Address.Low, ! dmap->addr.address64.Low); ! ddi_put32(acc_hdl, &sge->Address.High, ! dmap->addr.address64.High); ! ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count); flags = ddi_get32(acc_hdl, &sge->FlagsLength); flags |= ((uint32_t) (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
*** 4236,4250 **** /* * If this is the last cookie, we set the flags * to indicate so */ if (cookiec == 0) { ! flags |= ! ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT ! | MPI2_SGE_FLAGS_END_OF_BUFFER ! | MPI2_SGE_FLAGS_END_OF_LIST) << ! MPI2_SGE_FLAGS_SHIFT); } if (cmd->cmd_flags & CFLAG_DMASEND) { flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT); } else { --- 4224,4234 ---- /* * If this is the last cookie, we set the flags * to indicate so */ if (cookiec == 0) { ! flags |= end_flags; } if (cmd->cmd_flags & CFLAG_DMASEND) { flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT); } else {
*** 4253,4263 **** } ddi_put32(acc_hdl, &sge->FlagsLength, flags); dmap++; sge++; } ! } else { /* * Hereby we start to deal with multiple frames. * The process is as follows: * 1. Determine how many frames are needed for SGL element * storage; Note that all frames are stored in contiguous --- 4237,4266 ---- } ddi_put32(acc_hdl, &sge->FlagsLength, flags); dmap++; sge++; } ! } ! ! static void ! mptsas_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd, ! pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) ! { ! pMpi2SGESimple64_t sge; ! pMpi2SGEChain64_t sgechain; ! uint64_t nframe_phys_addr; ! uint_t cookiec; ! mptti_t *dmap; ! uint32_t flags; ! int i, j, k, l, frames, sgemax; ! int temp, maxframe_sges; ! uint8_t chainflags; ! uint16_t chainlength; ! mptsas_cache_frames_t *p; ! ! cookiec = cmd->cmd_cookiec; ! /* * Hereby we start to deal with multiple frames. * The process is as follows: * 1. Determine how many frames are needed for SGL element * storage; Note that all frames are stored in contiguous
*** 4284,4315 **** * hold SGL elements with the last 1 or 2 double-words * (4 or 8 bytes) un-used. On these controllers, we should * recognize that there's not enough room for another SGL * element and move the sge pointer to the next frame. */ - int i, j, k, l, frames, sgemax; - int temp; - uint8_t chainflags; - uint16_t chainlength; - mptsas_cache_frames_t *p; /* * Sgemax is the number of SGE's that will fit * each extra frame and frames is total * number of frames we'll need. 1 sge entry per * frame is reseverd for the chain element thus the -1 below. */ ! sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64)) ! - 1); ! temp = (cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) / sgemax; /* * A little check to see if we need to round up the number * of frames we need */ ! if ((cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) - (temp * ! sgemax) > 1) { frames = (temp + 1); } else { frames = temp; } dmap = cmd->cmd_sg; --- 4287,4312 ---- * hold SGL elements with the last 1 or 2 double-words * (4 or 8 bytes) un-used. On these controllers, we should * recognize that there's not enough room for another SGL * element and move the sge pointer to the next frame. */ /* * Sgemax is the number of SGE's that will fit * each extra frame and frames is total * number of frames we'll need. 1 sge entry per * frame is reseverd for the chain element thus the -1 below. */ ! sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64)) - 1); ! maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt); ! temp = (cookiec - (maxframe_sges - 1)) / sgemax; /* * A little check to see if we need to round up the number * of frames we need */ ! if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) { frames = (temp + 1); } else { frames = temp; } dmap = cmd->cmd_sg;
*** 4316,4361 **** sge = (pMpi2SGESimple64_t)(&frame->SGL); /* * First fill in the main frame */ ! for (j = 1; j < MPTSAS_MAX_FRAME_SGES64(mpt); j++) { ! ddi_put32(acc_hdl, &sge->Address.Low, ! dmap->addr.address64.Low); ! ddi_put32(acc_hdl, &sge->Address.High, ! dmap->addr.address64.High); ! ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count); ! flags = ddi_get32(acc_hdl, &sge->FlagsLength); ! flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_SGE_FLAGS_SYSTEM_ADDRESS | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << ! MPI2_SGE_FLAGS_SHIFT); /* - * If this is the last SGE of this frame - * we set the end of list flag - */ - if (j == (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) { - flags |= ((uint32_t) - (MPI2_SGE_FLAGS_LAST_ELEMENT) << - MPI2_SGE_FLAGS_SHIFT); - } - if (cmd->cmd_flags & CFLAG_DMASEND) { - flags |= - (MPI2_SGE_FLAGS_HOST_TO_IOC << - MPI2_SGE_FLAGS_SHIFT); - } else { - flags |= - (MPI2_SGE_FLAGS_IOC_TO_HOST << - MPI2_SGE_FLAGS_SHIFT); - } - ddi_put32(acc_hdl, &sge->FlagsLength, flags); - dmap++; - sge++; - } - - /* * Fill in the chain element in the main frame. * About calculation on ChainOffset: * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes) * in the end reserved for SGL element storage * (MPI2_SGE_IO_UNION); we should count it in our --- 4313,4331 ---- sge = (pMpi2SGESimple64_t)(&frame->SGL); /* * First fill in the main frame */ ! j = maxframe_sges - 1; ! mptsas_sge_mainframe(cmd, frame, acc_hdl, j, ! ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT) << ! MPI2_SGE_FLAGS_SHIFT)); ! dmap += j; ! sge += j; ! j++; /* * Fill in the chain element in the main frame. * About calculation on ChainOffset: * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes) * in the end reserved for SGL element storage * (MPI2_SGE_IO_UNION); we should count it in our
*** 4394,4406 **** p = cmd->cmd_extra_frames; ddi_put16(acc_hdl, &sgechain->Length, chainlength); ddi_put32(acc_hdl, &sgechain->Address.Low, ! p->m_phys_addr); ! /* SGL is allocated in the first 4G mem range */ ! ddi_put32(acc_hdl, &sgechain->Address.High, 0); /* * If there are more than 2 frames left we have to * fill in the next chain offset to the location of * the chain element in the next frame. --- 4364,4375 ---- p = cmd->cmd_extra_frames; ddi_put16(acc_hdl, &sgechain->Length, chainlength); ddi_put32(acc_hdl, &sgechain->Address.Low, ! (p->m_phys_addr&0xffffffffull)); ! ddi_put32(acc_hdl, &sgechain->Address.High, p->m_phys_addr>>32); /* * If there are more than 2 frames left we have to * fill in the next chain offset to the location of * the chain element in the next frame.
*** 4454,4469 **** * k is the frame counter and (k + 1) * is the number of the next frame. * Note that frames are in contiguous * memory space. */ ddi_put32(p->m_acc_hdl, &sgechain->Address.Low, ! (p->m_phys_addr + ! (mpt->m_req_frame_size * k))); ddi_put32(p->m_acc_hdl, ! &sgechain->Address.High, 0); /* * If there are more than 2 frames left * we have to next chain offset to * the location of the chain element --- 4423,4440 ---- * k is the frame counter and (k + 1) * is the number of the next frame. * Note that frames are in contiguous * memory space. */ + nframe_phys_addr = p->m_phys_addr + + (mpt->m_req_frame_size * k); ddi_put32(p->m_acc_hdl, &sgechain->Address.Low, ! nframe_phys_addr&0xffffffffull); ddi_put32(p->m_acc_hdl, ! &sgechain->Address.High, ! nframe_phys_addr>>32); /* * If there are more than 2 frames left * we have to next chain offset to * the location of the chain element
*** 4562,4574 **** --- 4533,4911 ---- /* * Sync DMA with the chain buffers that were just created */ (void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); + } + + static void + mptsas_ieee_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame, + ddi_acc_handle_t acc_hdl, uint_t cookiec, + uint8_t end_flag) + { + pMpi2IeeeSgeSimple64_t ieeesge; + mptti_t *dmap; + uint8_t flags; + + dmap = cmd->cmd_sg; + + NDBG1(("mptsas_ieee_sge_mainframe: cookiec=%d, %s", cookiec, + cmd->cmd_flags & CFLAG_DMASEND?"Out":"In")); + + ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL); + while (cookiec--) { + ddi_put32(acc_hdl, &ieeesge->Address.Low, + dmap->addr.address64.Low); + ddi_put32(acc_hdl, &ieeesge->Address.High, + dmap->addr.address64.High); + ddi_put32(acc_hdl, &ieeesge->Length, dmap->count); + NDBG1(("mptsas_ieee_sge_mainframe: len=%d", dmap->count)); + flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + + /* + * If this is the last cookie, we set the flags + * to indicate so + */ + if (cookiec == 0) { + flags |= end_flag; } + + /* + * XXX: Hmmm, what about the direction based on + * cmd->cmd_flags & CFLAG_DMASEND? + */ + ddi_put8(acc_hdl, &ieeesge->Flags, flags); + dmap++; + ieeesge++; + } } + static void + mptsas_ieee_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd, + pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) + { + pMpi2IeeeSgeSimple64_t ieeesge; + pMpi25IeeeSgeChain64_t ieeesgechain; + uint64_t nframe_phys_addr; + uint_t cookiec; + mptti_t *dmap; + uint8_t flags; + int i, j, k, l, frames, sgemax; + int temp, maxframe_sges; + uint8_t chainflags; + uint32_t chainlength; + mptsas_cache_frames_t *p; + + cookiec = cmd->cmd_cookiec; + + NDBG1(("mptsas_ieee_sge_chain: cookiec=%d", cookiec)); + + /* + * Hereby we start to deal with multiple frames. + * The process is as follows: + * 1. Determine how many frames are needed for SGL element + * storage; Note that all frames are stored in contiguous + * memory space and in 64-bit DMA mode each element is + * 4 double-words (16 bytes) long. + * 2. Fill up the main frame. We need to do this separately + * since it contains the SCSI IO request header and needs + * dedicated processing. Note that the last 4 double-words + * of the SCSI IO header is for SGL element storage + * (MPI2_SGE_IO_UNION). + * 3. Fill the chain element in the main frame, so the DMA + * engine can use the following frames. + * 4. Enter a loop to fill the remaining frames. Note that the + * last frame contains no chain element. The remaining + * frames go into the mpt SGL buffer allocated on the fly, + * not immediately following the main message frame, as in + * Gen1. + * Some restrictions: + * 1. For 64-bit DMA, the simple element and chain element + * are both of 4 double-words (16 bytes) in size, even + * though all frames are stored in the first 4G of mem + * range and the higher 32-bits of the address are always 0. + * 2. On some controllers (like the 1064/1068), a frame can + * hold SGL elements with the last 1 or 2 double-words + * (4 or 8 bytes) un-used. On these controllers, we should + * recognize that there's not enough room for another SGL + * element and move the sge pointer to the next frame. + */ + + /* + * Sgemax is the number of SGE's that will fit + * each extra frame and frames is total + * number of frames we'll need. 1 sge entry per + * frame is reseverd for the chain element thus the -1 below. + */ + sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_IEEE_SGE_SIMPLE64)) + - 1); + maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt); + temp = (cookiec - (maxframe_sges - 1)) / sgemax; + + /* + * A little check to see if we need to round up the number + * of frames we need + */ + if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) { + frames = (temp + 1); + } else { + frames = temp; + } + NDBG1(("mptsas_ieee_sge_chain: temp=%d, frames=%d", temp, frames)); + dmap = cmd->cmd_sg; + ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL); + + /* + * First fill in the main frame + */ + j = maxframe_sges - 1; + mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl, j, 0); + dmap += j; + ieeesge += j; + j++; + + /* + * Fill in the chain element in the main frame. + * About calculation on ChainOffset: + * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes) + * in the end reserved for SGL element storage + * (MPI2_SGE_IO_UNION); we should count it in our + * calculation. See its definition in the header file. + * 2. Constant j is the counter of the current SGL element + * that will be processed, and (j - 1) is the number of + * SGL elements that have been processed (stored in the + * main frame). + * 3. ChainOffset value should be in units of quad-words (16 + * bytes) so the last value should be divided by 16. + */ + ddi_put8(acc_hdl, &frame->ChainOffset, + (sizeof (MPI2_SCSI_IO_REQUEST) - + sizeof (MPI2_SGE_IO_UNION) + + (j - 1) * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4); + ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge; + chainflags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + ddi_put8(acc_hdl, &ieeesgechain->Flags, chainflags); + + /* + * The size of the next frame is the accurate size of space + * (in bytes) used to store the SGL elements. j is the counter + * of SGL elements. (j - 1) is the number of SGL elements that + * have been processed (stored in frames). + */ + if (frames >= 2) { + chainlength = mpt->m_req_frame_size / + sizeof (MPI2_IEEE_SGE_SIMPLE64) * + sizeof (MPI2_IEEE_SGE_SIMPLE64); + } else { + chainlength = ((cookiec - (j - 1)) * + sizeof (MPI2_IEEE_SGE_SIMPLE64)); + } + + p = cmd->cmd_extra_frames; + + ddi_put32(acc_hdl, &ieeesgechain->Length, chainlength); + ddi_put32(acc_hdl, &ieeesgechain->Address.Low, + p->m_phys_addr&0xffffffffull); + ddi_put32(acc_hdl, &ieeesgechain->Address.High, p->m_phys_addr>>32); + + /* + * If there are more than 2 frames left we have to + * fill in the next chain offset to the location of + * the chain element in the next frame. + * sgemax is the number of simple elements in an extra + * frame. Note that the value NextChainOffset should be + * in double-words (4 bytes). + */ + if (frames >= 2) { + ddi_put8(acc_hdl, &ieeesgechain->NextChainOffset, + (sgemax * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4); + } else { + ddi_put8(acc_hdl, &ieeesgechain->NextChainOffset, 0); + } + + /* + * Jump to next frame; + * Starting here, chain buffers go into the per command SGL. + * This buffer is allocated when chain buffers are needed. + */ + ieeesge = (pMpi2IeeeSgeSimple64_t)p->m_frames_addr; + i = cookiec; + + /* + * Start filling in frames with SGE's. If we + * reach the end of frame and still have SGE's + * to fill we need to add a chain element and + * use another frame. j will be our counter + * for what cookie we are at and i will be + * the total cookiec. k is the current frame + */ + for (k = 1; k <= frames; k++) { + for (l = 1; (l <= (sgemax + 1)) && (j <= i); j++, l++) { + + /* + * If we have reached the end of frame + * and we have more SGE's to fill in + * we have to fill the final entry + * with a chain element and then + * continue to the next frame + */ + if ((l == (sgemax + 1)) && (k != frames)) { + ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge; + j--; + chainflags = + MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; + ddi_put8(p->m_acc_hdl, + &ieeesgechain->Flags, chainflags); + /* + * k is the frame counter and (k + 1) + * is the number of the next frame. + * Note that frames are in contiguous + * memory space. + */ + nframe_phys_addr = p->m_phys_addr + + (mpt->m_req_frame_size * k); + ddi_put32(p->m_acc_hdl, + &ieeesgechain->Address.Low, + nframe_phys_addr&0xffffffffull); + ddi_put32(p->m_acc_hdl, + &ieeesgechain->Address.High, + nframe_phys_addr>>32); + + /* + * If there are more than 2 frames left + * we have to next chain offset to + * the location of the chain element + * in the next frame and fill in the + * length of the next chain + */ + if ((frames - k) >= 2) { + ddi_put8(p->m_acc_hdl, + &ieeesgechain->NextChainOffset, + (sgemax * + sizeof (MPI2_IEEE_SGE_SIMPLE64)) + >> 4); + ddi_put32(p->m_acc_hdl, + &ieeesgechain->Length, + mpt->m_req_frame_size / + sizeof (MPI2_IEEE_SGE_SIMPLE64) * + sizeof (MPI2_IEEE_SGE_SIMPLE64)); + } else { + /* + * This is the last frame. Set + * the NextChainOffset to 0 and + * Length is the total size of + * all remaining simple elements + */ + ddi_put8(p->m_acc_hdl, + &ieeesgechain->NextChainOffset, + 0); + ddi_put32(p->m_acc_hdl, + &ieeesgechain->Length, + (cookiec - j) * + sizeof (MPI2_IEEE_SGE_SIMPLE64)); + } + + /* Jump to the next frame */ + ieeesge = (pMpi2IeeeSgeSimple64_t) + ((char *)p->m_frames_addr + + (int)mpt->m_req_frame_size * k); + + continue; + } + + ddi_put32(p->m_acc_hdl, + &ieeesge->Address.Low, + dmap->addr.address64.Low); + ddi_put32(p->m_acc_hdl, + &ieeesge->Address.High, + dmap->addr.address64.High); + ddi_put32(p->m_acc_hdl, + &ieeesge->Length, dmap->count); + flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + + /* + * If we are at the end of the frame and + * there is another frame to fill in + * do we need to do anything? + * if ((l == sgemax) && (k != frames)) { + * } + */ + + /* + * If this is the final cookie set end of list. + */ + if (j == i) { + flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; + } + + ddi_put8(p->m_acc_hdl, &ieeesge->Flags, flags); + dmap++; + ieeesge++; + } + } + + /* + * Sync DMA with the chain buffers that were just created + */ + (void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); + } + + static void + mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control, + pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) + { + ASSERT(cmd->cmd_flags & CFLAG_DMAVALID); + + NDBG1(("mptsas_sge_setup: cookiec=%d", cmd->cmd_cookiec)); + + /* + * Set read/write bit in control. + */ + if (cmd->cmd_flags & CFLAG_DMASEND) { + *control |= MPI2_SCSIIO_CONTROL_WRITE; + } else { + *control |= MPI2_SCSIIO_CONTROL_READ; + } + + ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount); + + /* + * We have 4 cases here. First where we can fit all the + * SG elements into the main frame, and the case + * where we can't. The SG element is also different when using + * MPI2.5 interface. + * If we have more cookies than we can attach to a frame + * we will need to use a chain element to point + * a location of memory where the rest of the S/G + * elements reside. + */ + if (cmd->cmd_cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) { + if (mpt->m_MPI25) { + mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl, + cmd->cmd_cookiec, + MPI25_IEEE_SGE_FLAGS_END_OF_LIST); + } else { + mptsas_sge_mainframe(cmd, frame, acc_hdl, + cmd->cmd_cookiec, + ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT + | MPI2_SGE_FLAGS_END_OF_BUFFER + | MPI2_SGE_FLAGS_END_OF_LIST) << + MPI2_SGE_FLAGS_SHIFT)); + } + } else { + if (mpt->m_MPI25) { + mptsas_ieee_sge_chain(mpt, cmd, frame, acc_hdl); + } else { + mptsas_sge_chain(mpt, cmd, frame, acc_hdl); + } + } + } + /* * Interrupt handling * Utility routine. Poll for status of a command sent to HBA * without interrupts (a FLAG_NOINTR command). */
*** 5489,5499 **** * after they've all been processed. */ reply_type = ddi_get8(mpt->m_acc_post_queue_hdl, &reply_desc_union->Default.ReplyFlags); reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; ! if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { mptsas_handle_scsi_io_success(mpt, reply_desc_union); } else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { mptsas_handle_address_reply(mpt, reply_desc_union); } else { mptsas_log(mpt, CE_WARN, "?Bad reply type %x", reply_type); --- 5826,5837 ---- * after they've all been processed. */ reply_type = ddi_get8(mpt->m_acc_post_queue_hdl, &reply_desc_union->Default.ReplyFlags); reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; ! if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS || ! reply_type == MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS) { mptsas_handle_scsi_io_success(mpt, reply_desc_union); } else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { mptsas_handle_address_reply(mpt, reply_desc_union); } else { mptsas_log(mpt, CE_WARN, "?Bad reply type %x", reply_type);
*** 9303,9313 **** va_end(ap); #ifdef PROM_PRINTF prom_printf("%s:\t%s\n", mptsas_label, mptsas_log_buf); #else ! scsi_log(dev, mptsas_label, SCSI_DEBUG, "%s\n", mptsas_log_buf); #endif mutex_exit(&mptsas_log_mutex); } #endif --- 9641,9651 ---- va_end(ap); #ifdef PROM_PRINTF prom_printf("%s:\t%s\n", mptsas_label, mptsas_log_buf); #else ! scsi_log(dev, mptsas_label, CE_CONT, "!%s\n", mptsas_log_buf); #endif mutex_exit(&mptsas_log_mutex); } #endif
*** 9665,9764 **** NDBG25(("?pkt_scbp=0x%x cmd_flags=0x%x\n", cmd->cmd_pkt->pkt_scbp ? *(cmd->cmd_pkt->pkt_scbp) : 0, cmd->cmd_flags)); } static void ! mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd) { ! caddr_t memp; ! pMPI2RequestHeader_t request_hdrp; ! struct scsi_pkt *pkt = cmd->cmd_pkt; ! mptsas_pt_request_t *pt = pkt->pkt_ha_private; ! uint32_t request_size, data_size, dataout_size; ! uint32_t direction; ddi_dma_cookie_t data_cookie; ddi_dma_cookie_t dataout_cookie; - uint32_t request_desc_low, request_desc_high = 0; - uint32_t i, sense_bufp; - uint8_t desc_type; - uint8_t *request, function; - ddi_dma_handle_t dma_hdl = mpt->m_dma_req_frame_hdl; - ddi_acc_handle_t acc_hdl = mpt->m_acc_req_frame_hdl; - desc_type = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - - request = pt->request; - direction = pt->direction; - request_size = pt->request_size; data_size = pt->data_size; dataout_size = pt->dataout_size; data_cookie = pt->data_cookie; dataout_cookie = pt->dataout_cookie; - /* - * Store the passthrough message in memory location - * corresponding to our slot number - */ - memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot); - request_hdrp = (pMPI2RequestHeader_t)memp; - bzero(memp, mpt->m_req_frame_size); - - for (i = 0; i < request_size; i++) { - bcopy(request + i, memp + i, 1); - } - - if (data_size || dataout_size) { - pMpi2SGESimple64_t sgep; - uint32_t sge_flags; - - sgep = (pMpi2SGESimple64_t)((uint8_t *)request_hdrp + - request_size); if (dataout_size) { - sge_flags = dataout_size | ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << MPI2_SGE_FLAGS_SHIFT); ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags); ddi_put32(acc_hdl, &sgep->Address.Low, ! (uint32_t)(dataout_cookie.dmac_laddress & ! 0xffffffffull)); ddi_put32(acc_hdl, &sgep->Address.High, ! (uint32_t)(dataout_cookie.dmac_laddress ! >> 32)); sgep++; } sge_flags = data_size; sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << MPI2_SGE_FLAGS_SHIFT); ! if (direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) { sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << MPI2_SGE_FLAGS_SHIFT); } else { sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << MPI2_SGE_FLAGS_SHIFT); } ! ddi_put32(acc_hdl, &sgep->FlagsLength, ! sge_flags); ddi_put32(acc_hdl, &sgep->Address.Low, ! (uint32_t)(data_cookie.dmac_laddress & ! 0xffffffffull)); ddi_put32(acc_hdl, &sgep->Address.High, (uint32_t)(data_cookie.dmac_laddress >> 32)); } function = request_hdrp->Function; if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { pMpi2SCSIIORequest_t scsi_io_req; scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp; /* * Put SGE for data and data_out buffer at the end of * scsi_io_request message header.(64 bytes in total) * Following above SGEs, the residual space will be --- 10003,10149 ---- NDBG25(("?pkt_scbp=0x%x cmd_flags=0x%x\n", cmd->cmd_pkt->pkt_scbp ? *(cmd->cmd_pkt->pkt_scbp) : 0, cmd->cmd_flags)); } static void ! mptsas_passthru_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt, ! pMpi2SGESimple64_t sgep) { ! uint32_t sge_flags; ! uint32_t data_size, dataout_size; ddi_dma_cookie_t data_cookie; ddi_dma_cookie_t dataout_cookie; data_size = pt->data_size; dataout_size = pt->dataout_size; data_cookie = pt->data_cookie; dataout_cookie = pt->dataout_cookie; if (dataout_size) { sge_flags = dataout_size | ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << MPI2_SGE_FLAGS_SHIFT); ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags); ddi_put32(acc_hdl, &sgep->Address.Low, ! (uint32_t)(dataout_cookie.dmac_laddress & 0xffffffffull)); ddi_put32(acc_hdl, &sgep->Address.High, ! (uint32_t)(dataout_cookie.dmac_laddress >> 32)); sgep++; } sge_flags = data_size; sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << MPI2_SGE_FLAGS_SHIFT); ! if (pt->direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) { sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << MPI2_SGE_FLAGS_SHIFT); } else { sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << MPI2_SGE_FLAGS_SHIFT); } ! ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags); ddi_put32(acc_hdl, &sgep->Address.Low, ! (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull)); ddi_put32(acc_hdl, &sgep->Address.High, (uint32_t)(data_cookie.dmac_laddress >> 32)); + } + + static void + mptsas_passthru_ieee_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt, + pMpi2IeeeSgeSimple64_t ieeesgep) + { + uint8_t sge_flags; + uint32_t data_size, dataout_size; + ddi_dma_cookie_t data_cookie; + ddi_dma_cookie_t dataout_cookie; + + data_size = pt->data_size; + dataout_size = pt->dataout_size; + data_cookie = pt->data_cookie; + dataout_cookie = pt->dataout_cookie; + + sge_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + if (dataout_size) { + ddi_put32(acc_hdl, &ieeesgep->Length, dataout_size); + ddi_put32(acc_hdl, &ieeesgep->Address.Low, + (uint32_t)(dataout_cookie.dmac_laddress & + 0xffffffffull)); + ddi_put32(acc_hdl, &ieeesgep->Address.High, + (uint32_t)(dataout_cookie.dmac_laddress >> 32)); + ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags); + ieeesgep++; } + sge_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; + ddi_put32(acc_hdl, &ieeesgep->Length, data_size); + ddi_put32(acc_hdl, &ieeesgep->Address.Low, + (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull)); + ddi_put32(acc_hdl, &ieeesgep->Address.High, + (uint32_t)(data_cookie.dmac_laddress >> 32)); + ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags); + } + static void + mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd) + { + caddr_t memp; + pMPI2RequestHeader_t request_hdrp; + struct scsi_pkt *pkt = cmd->cmd_pkt; + mptsas_pt_request_t *pt = pkt->pkt_ha_private; + uint32_t request_size; + uint32_t request_desc_low, request_desc_high = 0; + uint64_t sense_bufp; + uint8_t desc_type; + uint8_t *request, function; + ddi_dma_handle_t dma_hdl = mpt->m_dma_req_frame_hdl; + ddi_acc_handle_t acc_hdl = mpt->m_acc_req_frame_hdl; + + desc_type = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + request = pt->request; + request_size = pt->request_size; + + /* + * Store the passthrough message in memory location + * corresponding to our slot number + */ + memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot); + request_hdrp = (pMPI2RequestHeader_t)memp; + bzero(memp, mpt->m_req_frame_size); + + bcopy(request, memp, request_size); + + NDBG15(("mptsas_start_passthru: Func 0x%x, MsgFlags 0x%x, " + "size=%d, in %d, out %d", request_hdrp->Function, + request_hdrp->MsgFlags, request_size, + pt->data_size, pt->dataout_size)); + + /* + * Add an SGE, even if the length is zero. + */ + if (mpt->m_MPI25 && pt->simple == 0) { + mptsas_passthru_ieee_sge(acc_hdl, pt, + (pMpi2IeeeSgeSimple64_t) + ((uint8_t *)request_hdrp + pt->sgl_offset)); + } else { + mptsas_passthru_sge(acc_hdl, pt, + (pMpi2SGESimple64_t) + ((uint8_t *)request_hdrp + pt->sgl_offset)); + } + function = request_hdrp->Function; if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { pMpi2SCSIIORequest_t scsi_io_req; + NDBG15(("mptsas_start_passthru: Is SCSI IO Req")); scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp; /* * Put SGE for data and data_out buffer at the end of * scsi_io_request message header.(64 bytes in total) * Following above SGEs, the residual space will be
*** 9766,9777 **** */ ddi_put8(acc_hdl, &scsi_io_req->SenseBufferLength, (uint8_t)(request_size - 64)); ! sense_bufp = mpt->m_req_frame_dma_addr + ! (mpt->m_req_frame_size * cmd->cmd_slot); sense_bufp += 64; ddi_put32(acc_hdl, &scsi_io_req->SenseBufferLowAddress, sense_bufp); /* --- 10151,10162 ---- */ ddi_put8(acc_hdl, &scsi_io_req->SenseBufferLength, (uint8_t)(request_size - 64)); ! sense_bufp = (uint32_t)(mpt->m_req_frame_dma_addr + ! (mpt->m_req_frame_size * cmd->cmd_slot) & 0xffffffffull); sense_bufp += 64; ddi_put32(acc_hdl, &scsi_io_req->SenseBufferLowAddress, sense_bufp); /*
*** 9805,9820 **** (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); } } static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint32_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode) { mptsas_pt_request_t pt; mptsas_dma_alloc_state_t data_dma_state; mptsas_dma_alloc_state_t dataout_dma_state; --- 10190,10566 ---- (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); } } + typedef void (mptsas_pre_f)(mptsas_t *, mptsas_pt_request_t *); + static mptsas_pre_f mpi_pre_ioc_facts; + static mptsas_pre_f mpi_pre_port_facts; + static mptsas_pre_f mpi_pre_fw_download; + static mptsas_pre_f mpi_pre_fw_25_download; + static mptsas_pre_f mpi_pre_fw_upload; + static mptsas_pre_f mpi_pre_fw_25_upload; + static mptsas_pre_f mpi_pre_sata_passthrough; + static mptsas_pre_f mpi_pre_smp_passthrough; + static mptsas_pre_f mpi_pre_config; + static mptsas_pre_f mpi_pre_sas_io_unit_control; + static mptsas_pre_f mpi_pre_scsi_io_req; + /* + * Prepare the pt for a SAS2 FW_DOWNLOAD request. + */ + static void + mpi_pre_fw_download(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWDownloadTCSGE_t tcsge; + pMpi2FWDownloadRequest req; + /* + * If SAS3, call separate function. + */ + if (mpt->m_MPI25) { + mpi_pre_fw_25_download(mpt, pt); + return; + } + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. Putting the + * SGL after that seems to work, but don't really know + * why. Other drivers tend to create an extra SGL and + * refer to the TCE through that. + */ + req = (pMpi2FWDownloadRequest)pt->request; + tcsge = (pMpi2FWDownloadTCSGE_t)&req->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Download tce invalid!"); + } + + pt->sgl_offset = offsetof(MPI2_FW_DOWNLOAD_REQUEST, SGL) + + sizeof (*tcsge); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_download(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + (int)pt->request_size, (int)pt->sgl_offset, + (int)pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY)) + NDBG15(("mpi_pre_fw_download(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_DOWNLOAD_REPLY))); + } + + /* + * Prepare the pt for a SAS3 FW_DOWNLOAD request. + */ + static void + mpi_pre_fw_25_download(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWDownloadTCSGE_t tcsge; + pMpi2FWDownloadRequest req2; + pMpi25FWDownloadRequest req25; + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. The new firmware + * Doesn't use TCE and has space in the main request for + * this information. So move to the right place. + */ + req2 = (pMpi2FWDownloadRequest)pt->request; + req25 = (pMpi25FWDownloadRequest)pt->request; + tcsge = (pMpi2FWDownloadTCSGE_t)&req2->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Download tce invalid!"); + } + req25->ImageOffset = tcsge->ImageOffset; + req25->ImageSize = tcsge->ImageSize; + + pt->sgl_offset = offsetof(MPI25_FW_DOWNLOAD_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_25_download(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY)) + NDBG15(("mpi_pre_fw_25_download(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_UPLOAD_REPLY))); + } + + /* + * Prepare the pt for a SAS2 FW_UPLOAD request. + */ + static void + mpi_pre_fw_upload(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWUploadTCSGE_t tcsge; + pMpi2FWUploadRequest_t req; + + /* + * If SAS3, call separate function. + */ + if (mpt->m_MPI25) { + mpi_pre_fw_25_upload(mpt, pt); + return; + } + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. Putting the + * SGL after that seems to work, but don't really know + * why. Other drivers tend to create an extra SGL and + * refer to the TCE through that. + */ + req = (pMpi2FWUploadRequest_t)pt->request; + tcsge = (pMpi2FWUploadTCSGE_t)&req->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!"); + } + + pt->sgl_offset = offsetof(MPI2_FW_UPLOAD_REQUEST, SGL) + + sizeof (*tcsge); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_upload(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY)) + NDBG15(("mpi_pre_fw_upload(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_UPLOAD_REPLY))); + } + + /* + * Prepare the pt a SAS3 FW_UPLOAD request. + */ + static void + mpi_pre_fw_25_upload(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWUploadTCSGE_t tcsge; + pMpi2FWUploadRequest_t req2; + pMpi25FWUploadRequest_t req25; + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. The new firmware + * Doesn't use TCE and has space in the main request for + * this information. So move to the right place. + */ + req2 = (pMpi2FWUploadRequest_t)pt->request; + req25 = (pMpi25FWUploadRequest_t)pt->request; + tcsge = (pMpi2FWUploadTCSGE_t)&req2->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!"); + } + req25->ImageOffset = tcsge->ImageOffset; + req25->ImageSize = tcsge->ImageSize; + + pt->sgl_offset = offsetof(MPI25_FW_UPLOAD_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_25_upload(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY)) + NDBG15(("mpi_pre_fw_25_upload(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_UPLOAD_REPLY))); + } + + /* + * Prepare the pt for an IOC_FACTS request. + */ + static void + mpi_pre_ioc_facts(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + if (pt->request_size != sizeof (MPI2_IOC_FACTS_REQUEST)) + NDBG15(("mpi_pre_ioc_facts(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, + (int)sizeof (MPI2_IOC_FACTS_REQUEST), + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_IOC_FACTS_REPLY)) + NDBG15(("mpi_pre_ioc_facts(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_IOC_FACTS_REPLY))); + pt->sgl_offset = (uint16_t)pt->request_size; + } + + /* + * Prepare the pt for a PORT_FACTS request. + */ + static void + mpi_pre_port_facts(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + if (pt->request_size != sizeof (MPI2_PORT_FACTS_REQUEST)) + NDBG15(("mpi_pre_port_facts(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, + (int)sizeof (MPI2_PORT_FACTS_REQUEST), + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_PORT_FACTS_REPLY)) + NDBG15(("mpi_pre_port_facts(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_PORT_FACTS_REPLY))); + pt->sgl_offset = (uint16_t)pt->request_size; + } + + /* + * Prepare pt for a SATA_PASSTHROUGH request. + */ + static void + mpi_pre_sata_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_SATA_PASSTHROUGH_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_sata_passthrough(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_SATA_PASSTHROUGH_REPLY)) + NDBG15(("mpi_pre_sata_passthrough(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_SATA_PASSTHROUGH_REPLY))); + } + + static void + mpi_pre_smp_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_SMP_PASSTHROUGH_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_smp_passthrough(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_SMP_PASSTHROUGH_REPLY)) + NDBG15(("mpi_pre_smp_passthrough(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_SMP_PASSTHROUGH_REPLY))); + } + + /* + * Prepare pt for a CONFIG request. + */ + static void + mpi_pre_config(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_CONFIG_REQUEST, PageBufferSGE); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, " + "should be 0x%x, dataoutsz 0x%x", pt->request_size, + pt->sgl_offset, pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_CONFIG_REPLY)) + NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, " + "should be 0x%x", pt->data_size, + (int)sizeof (MPI2_CONFIG_REPLY))); + pt->simple = 1; + } + + /* + * Prepare pt for a SCSI_IO_REQ request. + */ + static void + mpi_pre_scsi_io_req(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_SCSI_IO_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, " + "should be 0x%x, dataoutsz 0x%x", pt->request_size, + pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_SCSI_IO_REPLY)) + NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, " + "should be 0x%x", pt->data_size, + (int)sizeof (MPI2_SCSI_IO_REPLY))); + } + + /* + * Prepare the mptsas_cmd for a SAS_IO_UNIT_CONTROL request. + */ + static void + mpi_pre_sas_io_unit_control(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = (uint16_t)pt->request_size; + } + + /* + * A set of functions to prepare an mptsas_cmd for the various + * supported requests. + */ + static struct mptsas_func { + U8 Function; + char *Name; + mptsas_pre_f *f_pre; + } mptsas_func_list[] = { + { MPI2_FUNCTION_IOC_FACTS, "IOC_FACTS", mpi_pre_ioc_facts }, + { MPI2_FUNCTION_PORT_FACTS, "PORT_FACTS", mpi_pre_port_facts }, + { MPI2_FUNCTION_FW_DOWNLOAD, "FW_DOWNLOAD", mpi_pre_fw_download }, + { MPI2_FUNCTION_FW_UPLOAD, "FW_UPLOAD", mpi_pre_fw_upload }, + { MPI2_FUNCTION_SATA_PASSTHROUGH, "SATA_PASSTHROUGH", + mpi_pre_sata_passthrough }, + { MPI2_FUNCTION_SMP_PASSTHROUGH, "SMP_PASSTHROUGH", + mpi_pre_smp_passthrough}, + { MPI2_FUNCTION_SCSI_IO_REQUEST, "SCSI_IO_REQUEST", + mpi_pre_scsi_io_req}, + { MPI2_FUNCTION_CONFIG, "CONFIG", mpi_pre_config}, + { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, "SAS_IO_UNIT_CONTROL", + mpi_pre_sas_io_unit_control }, + { 0xFF, NULL, NULL } /* list end */ + }; + + static void + mptsas_prep_sgl_offset(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMPI2RequestHeader_t hdr; + struct mptsas_func *f; + + hdr = (pMPI2RequestHeader_t)pt->request; + + for (f = mptsas_func_list; f->f_pre != NULL; f++) { + if (hdr->Function == f->Function) { + f->f_pre(mpt, pt); + NDBG15(("mptsas_prep_sgl_offset: Function %s," + " sgl_offset 0x%x", f->Name, + pt->sgl_offset)); + return; + } + } + NDBG15(("mptsas_prep_sgl_offset: Unknown Function 0x%02x," + " returning req_size 0x%x for sgl_offset", + hdr->Function, pt->request_size)); + pt->sgl_offset = (uint16_t)pt->request_size; + } + + static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint8_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode) { mptsas_pt_request_t pt; mptsas_dma_alloc_state_t data_dma_state; mptsas_dma_alloc_state_t dataout_dma_state;
*** 9887,9896 **** --- 10633,10644 ---- } } mutex_enter(&mpt->m_mutex); } } + else + bzero(&data_dma_state, sizeof (data_dma_state)); if (dataout_size != 0) { dataout_dma_state.size = dataout_size; if (mptsas_dma_alloc(mpt, &dataout_dma_state) != DDI_SUCCESS) { status = ENOMEM;
*** 9910,9919 **** --- 10658,10669 ---- goto out; } } mutex_enter(&mpt->m_mutex); } + else + bzero(&dataout_dma_state, sizeof (dataout_dma_state)); if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) { status = EAGAIN; mptsas_log(mpt, CE_NOTE, "event ack command pool is full"); goto out;
*** 9926,9940 **** --- 10676,10692 ---- cmd->ioc_cmd_slot = (uint32_t)(rvalue); pt.request = (uint8_t *)request_msg; pt.direction = direction; + pt.simple = 0; pt.request_size = request_size; pt.data_size = data_size; pt.dataout_size = dataout_size; pt.data_cookie = data_dma_state.cookie; pt.dataout_cookie = dataout_dma_state.cookie; + mptsas_prep_sgl_offset(mpt, &pt); /* * Form a blank cmd/pkt to store the acknowledgement message */ pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
*** 10143,10153 **** return (mptsas_do_passthru(mpt, (uint8_t *)((uintptr_t)data->PtrRequest), (uint8_t *)((uintptr_t)data->PtrReply), (uint8_t *)((uintptr_t)data->PtrData), data->RequestSize, data->ReplySize, ! data->DataSize, data->DataDirection, (uint8_t *)((uintptr_t)data->PtrDataOut), data->DataOutSize, data->Timeout, mode)); } else { return (EINVAL); } --- 10895,10905 ---- return (mptsas_do_passthru(mpt, (uint8_t *)((uintptr_t)data->PtrRequest), (uint8_t *)((uintptr_t)data->PtrReply), (uint8_t *)((uintptr_t)data->PtrData), data->RequestSize, data->ReplySize, ! data->DataSize, (uint8_t)data->DataDirection, (uint8_t *)((uintptr_t)data->PtrDataOut), data->DataOutSize, data->Timeout, mode)); } else { return (EINVAL); }
*** 11228,11238 **** mptsas_read_adapter_data(mptsas_t *mpt, mptsas_adapter_data_t *adapter_data) { char *driver_verstr = MPTSAS_MOD_STRING; mptsas_lookup_pci_data(mpt, adapter_data); ! adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS2; adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid; adapter_data->PCIDeviceHwRev = (uint32_t)mpt->m_revid; adapter_data->SubSystemId = (uint32_t)mpt->m_ssid; adapter_data->SubsystemVendorId = (uint32_t)mpt->m_svid; (void) strcpy((char *)&adapter_data->DriverVersion[0], driver_verstr); --- 11980,11992 ---- mptsas_read_adapter_data(mptsas_t *mpt, mptsas_adapter_data_t *adapter_data) { char *driver_verstr = MPTSAS_MOD_STRING; mptsas_lookup_pci_data(mpt, adapter_data); ! adapter_data->AdapterType = mpt->m_MPI25 ? ! MPTIOCTL_ADAPTER_TYPE_SAS3 : ! MPTIOCTL_ADAPTER_TYPE_SAS2; adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid; adapter_data->PCIDeviceHwRev = (uint32_t)mpt->m_revid; adapter_data->SubSystemId = (uint32_t)mpt->m_ssid; adapter_data->SubsystemVendorId = (uint32_t)mpt->m_svid; (void) strcpy((char *)&adapter_data->DriverVersion[0], driver_verstr);
*** 14980,14990 **** static int mptsas_smp_start(struct smp_pkt *smp_pkt) { uint64_t wwn; Mpi2SmpPassthroughRequest_t req; Mpi2SmpPassthroughReply_t rep; ! uint32_t direction = 0; mptsas_t *mpt; int ret; uint64_t tmp64; mpt = (mptsas_t *)smp_pkt->smp_pkt_address-> --- 15734,15744 ---- static int mptsas_smp_start(struct smp_pkt *smp_pkt) { uint64_t wwn; Mpi2SmpPassthroughRequest_t req; Mpi2SmpPassthroughReply_t rep; ! uint8_t direction = 0; mptsas_t *mpt; int ret; uint64_t tmp64; mpt = (mptsas_t *)smp_pkt->smp_pkt_address->