summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjimharris <jimharris@FreeBSD.org>2012-08-21 22:28:14 +0000
committerjimharris <jimharris@FreeBSD.org>2012-08-21 22:28:14 +0000
commit3715d30a3faa80b3990a448a25ebcb06803eb47b (patch)
tree723083404d26c6424568aa0b517da6334f74dc2b
parentaac78a84d92b54710e2e24cb25f2a89d9ad5ea34 (diff)
downloadFreeBSD-src-3715d30a3faa80b3990a448a25ebcb06803eb47b.zip
FreeBSD-src-3715d30a3faa80b3990a448a25ebcb06803eb47b.tar.gz
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
-rw-r--r--sys/dev/isci/isci.c8
-rw-r--r--sys/dev/isci/isci.h1
-rw-r--r--sys/dev/isci/isci_controller.c41
-rw-r--r--sys/dev/isci/scil/sati_unmap.c4
-rw-r--r--sys/dev/isci/scil/scif_sas_sati_binding.h11
-rw-r--r--sys/dev/isci/scil/scif_sas_stp_io_request.c2
6 files changed, 56 insertions, 11 deletions
diff --git a/sys/dev/isci/isci.c b/sys/dev/isci/isci.c
index 6a1b4a8..4d2f4bd 100644
--- a/sys/dev/isci/isci.c
+++ b/sys/dev/isci/isci.c
@@ -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
diff --git a/sys/dev/isci/isci.h b/sys/dev/isci/isci.h
index cdba7de..48236b9 100644
--- a/sys/dev/isci/isci.h
+++ b/sys/dev/isci/isci.h
@@ -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
diff --git a/sys/dev/isci/isci_controller.c b/sys/dev/isci/isci_controller.c
index 49785cb..1255201 100644
--- a/sys/dev/isci/isci_controller.c
+++ b/sys/dev/isci/isci_controller.c
@@ -145,6 +145,14 @@ void scif_cb_controller_stop_complete(SCI_CONTROLLER_HANDLE_T controller,
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(SCI_CONTROLLER_HANDLE_T controller,
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(SCI_CONTROLLER_HANDLE_T controller,
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 ISCI_CONTROLLER *controller,
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)
diff --git a/sys/dev/isci/scil/sati_unmap.c b/sys/dev/isci/scil/sati_unmap.c
index cc8327b..4cd6e9c 100644
--- a/sys/dev/isci/scil/sati_unmap.c
+++ b/sys/dev/isci/scil/sati_unmap.c
@@ -335,8 +335,8 @@ SATI_STATUS sati_unmap_initial_processing(
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
);
diff --git a/sys/dev/isci/scil/scif_sas_sati_binding.h b/sys/dev/isci/scil/scif_sas_sati_binding.h
index 99c9433..329efd7 100644
--- a/sys/dev/isci/scil/scif_sas_sati_binding.h
+++ b/sys/dev/isci/scil/scif_sas_sati_binding.h
@@ -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 \
); \
diff --git a/sys/dev/isci/scil/scif_sas_stp_io_request.c b/sys/dev/isci/scil/scif_sas_stp_io_request.c
index 36910bd..cca50c6 100644
--- a/sys/dev/isci/scil/scif_sas_stp_io_request.c
+++ b/sys/dev/isci/scil/scif_sas_stp_io_request.c
@@ -171,6 +171,8 @@ SCI_STATUS scif_sas_stp_io_request_constructed_complete_handler(
);
}
+ sati_sequence_terminate(&fw_io->parent.stp.sequence, fw_io, fw_io);
+
return SCI_SUCCESS;
}
/**
OpenPOWER on IntegriCloud