Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Aug 2012 22:28:14 +0000 (UTC)
From:      Jim Harris <jimharris@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r239545 - in head/sys/dev/isci: . scil
Message-ID:  <201208212228.q7LMSEPO017765@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jimharris
Date: Tue Aug 21 22:28:14 2012
New Revision: 239545
URL: http://svn.freebsd.org/changeset/base/239545

Log:
  Fix/add support for SCSI UNMAP to ATA DSM translation.
  
  This addresses kernel panic observed when sending SCSI UNMAP
  commands to SATA disks attached to isci(4).
  
  1) Flesh out callback routines to allocate/free buffers needed for
     translating SCSI UNMAP data to ATA DSM data.
  2) Add controller-level pool for storing buffers previously allocated
     for UNMAP translation, to lessen chance of no buffer available
     under memory pressure.
  3) Ensure driver properly handles case where buffer pool is empty
     and contigmalloc returns NULL.
  
  Sponsored by: Intel
  Reported by: Maksim Yevmenkin <max at netflix dot com>
  Discussed with:  scottl
  MFC after: 3 days

Modified:
  head/sys/dev/isci/isci.c
  head/sys/dev/isci/isci.h
  head/sys/dev/isci/isci_controller.c
  head/sys/dev/isci/scil/sati_unmap.c
  head/sys/dev/isci/scil/scif_sas_sati_binding.h
  head/sys/dev/isci/scil/scif_sas_stp_io_request.c

Modified: head/sys/dev/isci/isci.c
==============================================================================
--- head/sys/dev/isci/isci.c	Tue Aug 21 22:23:17 2012	(r239544)
+++ head/sys/dev/isci/isci.c	Tue Aug 21 22:28:14 2012	(r239545)
@@ -185,6 +185,7 @@ isci_detach(device_t device)
 	for (i = 0; i < isci->controller_count; i++) {
 		struct ISCI_CONTROLLER *controller = &isci->controllers[i];
 		SCI_STATUS status;
+		void *unmap_buffer;
 
 		if (controller->scif_controller_handle != NULL) {
 			scic_controller_disable_interrupts(
@@ -218,6 +219,13 @@ isci_detach(device_t device)
 
 		if (controller->remote_device_memory != NULL)
 			free(controller->remote_device_memory, M_ISCI);
+
+		while (1) {
+			sci_pool_get(controller->unmap_buffer_pool, unmap_buffer);
+			if (unmap_buffer == NULL)
+				break;
+			contigfree(unmap_buffer, PAGE_SIZE, M_ISCI);
+		}
 	}
 
 	/* The SCIF controllers have been stopped, so we can now

Modified: head/sys/dev/isci/isci.h
==============================================================================
--- head/sys/dev/isci/isci.h	Tue Aug 21 22:23:17 2012	(r239544)
+++ head/sys/dev/isci/isci.h	Tue Aug 21 22:28:14 2012	(r239545)
@@ -175,6 +175,7 @@ struct ISCI_CONTROLLER
 	SCI_POOL_CREATE(remote_device_pool, struct ISCI_REMOTE_DEVICE *, SCI_MAX_REMOTE_DEVICES);
 	SCI_POOL_CREATE(request_pool, struct ISCI_REQUEST *, SCI_MAX_IO_REQUESTS);
 	SCI_POOL_CREATE(timer_pool, struct ISCI_TIMER *, SCI_MAX_TIMERS);
+	SCI_POOL_CREATE(unmap_buffer_pool, void *, SCI_MAX_REMOTE_DEVICES);
 };
 
 struct ISCI_REQUEST

Modified: head/sys/dev/isci/isci_controller.c
==============================================================================
--- head/sys/dev/isci/isci_controller.c	Tue Aug 21 22:23:17 2012	(r239544)
+++ head/sys/dev/isci/isci_controller.c	Tue Aug 21 22:28:14 2012	(r239545)
@@ -145,6 +145,14 @@ void scif_cb_controller_stop_complete(SC
 	isci_controller->is_started = FALSE;
 }
 
+static void
+isci_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
+{
+	SCI_PHYSICAL_ADDRESS *phys_addr = arg;
+
+	*phys_addr = seg[0].ds_addr;
+}
+
 /**
  * @brief This method will be invoked to allocate memory dynamically.
  *
@@ -159,7 +167,29 @@ void scif_cb_controller_stop_complete(SC
 void scif_cb_controller_allocate_memory(SCI_CONTROLLER_HANDLE_T controller,
     SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde)
 {
+	struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
+	    sci_object_get_association(controller);
 
+	/*
+	 * Note this routine is only used for buffers needed to translate
+	 * SCSI UNMAP commands to ATA DSM commands for SATA disks.
+	 *
+	 * We first try to pull a buffer from the controller's pool, and only
+	 * call contigmalloc if one isn't there.
+	 */
+	if (!sci_pool_empty(isci_controller->unmap_buffer_pool)) {
+		sci_pool_get(isci_controller->unmap_buffer_pool,
+		    mde->virtual_address);
+	} else
+		mde->virtual_address = contigmalloc(PAGE_SIZE,
+		    M_ISCI, M_NOWAIT, 0, BUS_SPACE_MAXADDR,
+		    mde->constant_memory_alignment, 0);
+
+	if (mde->virtual_address != NULL)
+		bus_dmamap_load(isci_controller->buffer_dma_tag,
+		    NULL, mde->virtual_address, PAGE_SIZE,
+		    isci_single_map, &mde->physical_address,
+		    BUS_DMA_NOWAIT);
 }
 
 /**
@@ -176,7 +206,16 @@ void scif_cb_controller_allocate_memory(
 void scif_cb_controller_free_memory(SCI_CONTROLLER_HANDLE_T controller,
     SCI_PHYSICAL_MEMORY_DESCRIPTOR_T * mde)
 {
+	struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)
+	    sci_object_get_association(controller);
 
+	/*
+	 * Put the buffer back into the controller's buffer pool, rather
+	 * than invoking configfree.  This helps reduce chance we won't
+	 * have buffers available when system is under memory pressure.
+	 */ 
+	sci_pool_put(isci_controller->unmap_buffer_pool,
+	    mde->virtual_address);
 }
 
 void isci_controller_construct(struct ISCI_CONTROLLER *controller,
@@ -228,6 +267,8 @@ void isci_controller_construct(struct IS
 	for ( int i = 0; i < SCI_MAX_TIMERS; i++ ) {
 		sci_pool_put(controller->timer_pool, timer++);
 	}
+
+	sci_pool_initialize(controller->unmap_buffer_pool);
 }
 
 SCI_STATUS isci_controller_initialize(struct ISCI_CONTROLLER *controller)

Modified: head/sys/dev/isci/scil/sati_unmap.c
==============================================================================
--- head/sys/dev/isci/scil/sati_unmap.c	Tue Aug 21 22:23:17 2012	(r239544)
+++ head/sys/dev/isci/scil/sati_unmap.c	Tue Aug 21 22:28:14 2012	(r239545)
@@ -335,8 +335,8 @@ SATI_STATUS sati_unmap_initial_processin
       sati_scsi_sense_data_construct(
          sequence,
          scsi_io,
-         SCSI_STATUS_CHECK_CONDITION,
-         SCSI_SENSE_ABORTED_COMMAND,
+         SCSI_STATUS_BUSY,
+         SCSI_SENSE_NO_SENSE,
          SCSI_ASC_NO_ADDITIONAL_SENSE,
          SCSI_ASCQ_NO_ADDITIONAL_SENSE
       );

Modified: head/sys/dev/isci/scil/scif_sas_sati_binding.h
==============================================================================
--- head/sys/dev/isci/scil/scif_sas_sati_binding.h	Tue Aug 21 22:23:17 2012	(r239544)
+++ head/sys/dev/isci/scil/scif_sas_sati_binding.h	Tue Aug 21 22:28:14 2012	(r239545)
@@ -183,22 +183,16 @@ extern "C" {
 {                                                                 \
    SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
    SCI_PHYSICAL_MEMORY_DESCRIPTOR_T mde;                          \
-   SCI_PHYSICAL_ADDRESS phys_addr;                                \
    mde.virtual_address = NULL;                                    \
-   sci_cb_make_physical_address(mde.physical_address, 0, 0);      \
    sci_base_mde_construct(                                        \
       &mde, 4, length, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS    \
    );                                                             \
    scif_cb_controller_allocate_memory(                            \
       fw_request->device->domain->controller, &mde                \
    );                                                             \
-   scic_cb_io_request_get_physical_address(fw_request->device->domain->controller, \
-                                           NULL,                  \
-                                           mde.virtual_address,   \
-                                           &phys_addr);           \
    *(virt_address)       = mde.virtual_address;                      \
-   *(phys_address_low)   = sci_cb_physical_address_lower(phys_addr); \
-   *(phys_address_high)  = sci_cb_physical_address_upper(phys_addr); \
+   *(phys_address_low)   = sci_cb_physical_address_lower(mde.physical_address); \
+   *(phys_address_high)  = sci_cb_physical_address_upper(mde.physical_address); \
 }
 
 #define sati_cb_free_dma_buffer(scsi_io, virt_address)         \
@@ -206,7 +200,6 @@ extern "C" {
    SCIF_SAS_REQUEST_T* fw_request = (SCIF_SAS_REQUEST_T*)scsi_io; \
    SCI_PHYSICAL_MEMORY_DESCRIPTOR_T mde;                          \
    mde.virtual_address = virt_address;                         \
-   sci_cb_make_physical_address(mde.physical_address, 0, 0);      \
    sci_base_mde_construct(                                        \
       &mde, 4, 0, SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS         \
    );                                                             \

Modified: head/sys/dev/isci/scil/scif_sas_stp_io_request.c
==============================================================================
--- head/sys/dev/isci/scil/scif_sas_stp_io_request.c	Tue Aug 21 22:23:17 2012	(r239544)
+++ head/sys/dev/isci/scil/scif_sas_stp_io_request.c	Tue Aug 21 22:28:14 2012	(r239545)
@@ -171,6 +171,8 @@ SCI_STATUS scif_sas_stp_io_request_const
          );
    }
 
+   sati_sequence_terminate(&fw_io->parent.stp.sequence, fw_io, fw_io);
+
    return SCI_SUCCESS;
 }
 /**



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201208212228.q7LMSEPO017765>