xref: /freebsd/sys/dev/isci/scil/sati_unmap.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1f11c7f63SJim Harris /*-
2*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3*718cf2ccSPedro F. Giffuni  *
4f11c7f63SJim Harris  * This file is provided under a dual BSD/GPLv2 license.  When using or
5f11c7f63SJim Harris  * redistributing this file, you may do so under either license.
6f11c7f63SJim Harris  *
7f11c7f63SJim Harris  * GPL LICENSE SUMMARY
8f11c7f63SJim Harris  *
9f11c7f63SJim Harris  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10f11c7f63SJim Harris  *
11f11c7f63SJim Harris  * This program is free software; you can redistribute it and/or modify
12f11c7f63SJim Harris  * it under the terms of version 2 of the GNU General Public License as
13f11c7f63SJim Harris  * published by the Free Software Foundation.
14f11c7f63SJim Harris  *
15f11c7f63SJim Harris  * This program is distributed in the hope that it will be useful, but
16f11c7f63SJim Harris  * WITHOUT ANY WARRANTY; without even the implied warranty of
17f11c7f63SJim Harris  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18f11c7f63SJim Harris  * General Public License for more details.
19f11c7f63SJim Harris  *
20f11c7f63SJim Harris  * You should have received a copy of the GNU General Public License
21f11c7f63SJim Harris  * along with this program; if not, write to the Free Software
22f11c7f63SJim Harris  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23f11c7f63SJim Harris  * The full GNU General Public License is included in this distribution
24f11c7f63SJim Harris  * in the file called LICENSE.GPL.
25f11c7f63SJim Harris  *
26f11c7f63SJim Harris  * BSD LICENSE
27f11c7f63SJim Harris  *
28f11c7f63SJim Harris  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29f11c7f63SJim Harris  * All rights reserved.
30f11c7f63SJim Harris  *
31f11c7f63SJim Harris  * Redistribution and use in source and binary forms, with or without
32f11c7f63SJim Harris  * modification, are permitted provided that the following conditions
33f11c7f63SJim Harris  * are met:
34f11c7f63SJim Harris  *
35f11c7f63SJim Harris  *   * Redistributions of source code must retain the above copyright
36f11c7f63SJim Harris  *     notice, this list of conditions and the following disclaimer.
37f11c7f63SJim Harris  *   * Redistributions in binary form must reproduce the above copyright
38f11c7f63SJim Harris  *     notice, this list of conditions and the following disclaimer in
39f11c7f63SJim Harris  *     the documentation and/or other materials provided with the
40f11c7f63SJim Harris  *     distribution.
41f11c7f63SJim Harris  *
42f11c7f63SJim Harris  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43f11c7f63SJim Harris  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44f11c7f63SJim Harris  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45f11c7f63SJim Harris  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46f11c7f63SJim Harris  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47f11c7f63SJim Harris  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48f11c7f63SJim Harris  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49f11c7f63SJim Harris  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50f11c7f63SJim Harris  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51f11c7f63SJim Harris  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52f11c7f63SJim Harris  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53f11c7f63SJim Harris  */
54f11c7f63SJim Harris 
55f11c7f63SJim Harris #include <sys/cdefs.h>
56f11c7f63SJim Harris /**
57f11c7f63SJim Harris  * @file
58f11c7f63SJim Harris  * @brief This file contains the method implementations required to
59f11c7f63SJim Harris  *        translate the SCSI unmap command.
60f11c7f63SJim Harris  */
61f11c7f63SJim Harris 
62f11c7f63SJim Harris #if !defined(DISABLE_SATI_UNMAP)
63f11c7f63SJim Harris 
64f11c7f63SJim Harris #include <dev/isci/scil/sati_unmap.h>
65f11c7f63SJim Harris #include <dev/isci/scil/sati_callbacks.h>
66f11c7f63SJim Harris #include <dev/isci/scil/sati_translator_sequence.h>
67f11c7f63SJim Harris #include <dev/isci/scil/sati_util.h>
68f11c7f63SJim Harris #include <dev/isci/scil/intel_ata.h>
69f11c7f63SJim Harris #include <dev/isci/scil/intel_scsi.h>
70f11c7f63SJim Harris #include <dev/isci/scil/intel_sat.h>
71f11c7f63SJim Harris 
72f11c7f63SJim Harris //******************************************************************************
73f11c7f63SJim Harris //* P R I V A T E   M E T H O D S
74f11c7f63SJim Harris //******************************************************************************
75f11c7f63SJim Harris 
76f11c7f63SJim Harris /**
77f11c7f63SJim Harris  * @brief This method translates a given number of DSM
78f11c7f63SJim Harris  *        requests into DSM blocks based on the devices logical block size
79f11c7f63SJim Harris  *
80f11c7f63SJim Harris  * @return Number of DSM blocks required for the DSM descriptor count
81f11c7f63SJim Harris  */
sati_unmap_calculate_dsm_blocks(SATI_TRANSLATOR_SEQUENCE_T * sequence,U32 dsm_descriptor_count)82f11c7f63SJim Harris U32 sati_unmap_calculate_dsm_blocks(
83f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
84f11c7f63SJim Harris    U32                          dsm_descriptor_count
85f11c7f63SJim Harris )
86f11c7f63SJim Harris {
87f11c7f63SJim Harris    U32 blocks = (dsm_descriptor_count * sizeof(TRIM_PAIR))/sequence->device->logical_block_size;
88f11c7f63SJim Harris    if ((dsm_descriptor_count * sizeof(TRIM_PAIR)) % sequence->device->logical_block_size)
89f11c7f63SJim Harris    {
90f11c7f63SJim Harris        blocks++;
91f11c7f63SJim Harris    }
92f11c7f63SJim Harris    return blocks;
93f11c7f63SJim Harris }
94f11c7f63SJim Harris 
95f11c7f63SJim Harris /**
96f11c7f63SJim Harris  * @brief This method performs the SCSI Unmap command translation
97f11c7f63SJim Harris  *        functionality.
98f11c7f63SJim Harris  *        This includes:
99f11c7f63SJim Harris  *        - setting the command register
100f11c7f63SJim Harris  *        - setting the device head register
101f11c7f63SJim Harris  *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
102f11c7f63SJim Harris  *        For more information on the parameters passed to this method,
103f11c7f63SJim Harris  *        please reference sati_translate_command().
104f11c7f63SJim Harris  *
105f11c7f63SJim Harris  * @return Indicate if the method was successfully completed.
106f11c7f63SJim Harris  * @retval SATI_SUCCESS This is returned in all other cases.
107f11c7f63SJim Harris  */
sati_unmap_construct(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io,U32 sector_count)108f11c7f63SJim Harris SATI_STATUS sati_unmap_construct(
109f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
110f11c7f63SJim Harris    void                       * scsi_io,
111f11c7f63SJim Harris    void                       * ata_io,
112f11c7f63SJim Harris    U32                          sector_count
113f11c7f63SJim Harris )
114f11c7f63SJim Harris {
115f11c7f63SJim Harris    U8 * h2d_register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
116f11c7f63SJim Harris    U8 * d2h_register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
117f11c7f63SJim Harris 
118f11c7f63SJim Harris    sati_set_ata_command(h2d_register_fis, ATA_DATA_SET_MANAGEMENT);
119f11c7f63SJim Harris    sati_set_ata_features(h2d_register_fis, 0x01);
120f11c7f63SJim Harris    sati_set_ata_sector_count(h2d_register_fis, (U8)sector_count);
121f11c7f63SJim Harris    sati_set_ata_device_head(h2d_register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE);
122f11c7f63SJim Harris 
123f11c7f63SJim Harris    // Set the completion status since the core will not do that for
124f11c7f63SJim Harris    // the udma fast path.
125f11c7f63SJim Harris    sati_set_ata_status(d2h_register_fis, 0x00);
126f11c7f63SJim Harris 
127f11c7f63SJim Harris    // Set up the direction and protocol for SCIC
128f11c7f63SJim Harris    sequence->data_direction                 = SATI_DATA_DIRECTION_OUT;
129f11c7f63SJim Harris    sequence->protocol                       = SAT_PROTOCOL_UDMA_DATA_OUT;
130f11c7f63SJim Harris    // The UNMAP translation will always require a callback
131f11c7f63SJim Harris    // on every response so it can free memory if an error
132f11c7f63SJim Harris    // occurs.
133f11c7f63SJim Harris    sequence->is_translate_response_required = TRUE;
134f11c7f63SJim Harris 
135f11c7f63SJim Harris    ASSERT(sector_count < 0x100);
136f11c7f63SJim Harris 
137f11c7f63SJim Harris    return SATI_SUCCESS;
138f11c7f63SJim Harris }
139f11c7f63SJim Harris 
140f11c7f63SJim Harris /**
141f11c7f63SJim Harris  * @brief This method updates the unmap sequence state to the next
142f11c7f63SJim Harris  *        unmap descriptor
143f11c7f63SJim Harris  *
144f11c7f63SJim Harris  * @return Indicate if the method was successfully completed.
145f11c7f63SJim Harris  * @retval SATI_SUCCESS This is returned in all other cases.
146f11c7f63SJim Harris  */
sati_unmap_load_next_descriptor(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io)147f11c7f63SJim Harris SATI_STATUS sati_unmap_load_next_descriptor(
148f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
149f11c7f63SJim Harris    void                       * scsi_io
150f11c7f63SJim Harris )
151f11c7f63SJim Harris {
152f11c7f63SJim Harris    SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
153f11c7f63SJim Harris    U32                             index;
154f11c7f63SJim Harris    U8                              unmap_block_descriptor[16];
155f11c7f63SJim Harris 
156f11c7f63SJim Harris    unmap_process_state = &sequence->command_specific_data.unmap_process_state;
157f11c7f63SJim Harris 
158f11c7f63SJim Harris    // Load the next descriptor
159f11c7f63SJim Harris    for(index = unmap_process_state->current_unmap_block_descriptor_index;
160f11c7f63SJim Harris        index < unmap_process_state->current_unmap_block_descriptor_index +
161f11c7f63SJim Harris                SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
162f11c7f63SJim Harris        index++)
163f11c7f63SJim Harris    {
164f11c7f63SJim Harris       sati_get_data_byte(sequence,
165f11c7f63SJim Harris          scsi_io,
166f11c7f63SJim Harris          index,
167f11c7f63SJim Harris          &unmap_block_descriptor[index-unmap_process_state->current_unmap_block_descriptor_index]);
168f11c7f63SJim Harris    }
169f11c7f63SJim Harris 
170f11c7f63SJim Harris    // Update the internal state for the next translation pass
171f11c7f63SJim Harris    unmap_process_state->current_lba_count = (unmap_block_descriptor[8] << 24) |
172f11c7f63SJim Harris                                             (unmap_block_descriptor[9] << 16) |
173f11c7f63SJim Harris                                             (unmap_block_descriptor[10] << 8) |
174f11c7f63SJim Harris                                             (unmap_block_descriptor[11]);
175f11c7f63SJim Harris    unmap_process_state->current_lba       = ((SATI_LBA)(unmap_block_descriptor[0]) << 56) |
176f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[1]) << 48) |
177f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[2]) << 40) |
178f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[3]) << 32) |
179f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[4]) << 24) |
180f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[5]) << 16) |
181f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[6]) << 8) |
182f11c7f63SJim Harris                                             ((SATI_LBA)(unmap_block_descriptor[7]));
183f11c7f63SJim Harris    unmap_process_state->next_lba          = 0;
184f11c7f63SJim Harris 
185f11c7f63SJim Harris    // Update the index for the next descriptor to translate
186f11c7f63SJim Harris    unmap_process_state->current_unmap_block_descriptor_index += SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
187f11c7f63SJim Harris 
188f11c7f63SJim Harris    return SATI_SUCCESS;
189f11c7f63SJim Harris }
190f11c7f63SJim Harris 
191f11c7f63SJim Harris /**
192f11c7f63SJim Harris  * @brief This method determines the max number of blocks of DSM data
193f11c7f63SJim Harris  *        that can be satisfied by the device and the SW
194f11c7f63SJim Harris  *
195f11c7f63SJim Harris  * @return Number of blocks supported
196f11c7f63SJim Harris  * @retval Number of blocks supported
197f11c7f63SJim Harris  */
sati_unmap_get_max_buffer_size_in_blocks(SATI_TRANSLATOR_SEQUENCE_T * sequence)198f11c7f63SJim Harris U32 sati_unmap_get_max_buffer_size_in_blocks(
199f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence
200f11c7f63SJim Harris )
201f11c7f63SJim Harris {
202f11c7f63SJim Harris    // Currently this SATI implementation only supports a single
203f11c7f63SJim Harris    // 4k block of memory for the DMA write operation for simplicity
204f11c7f63SJim Harris    // (no need to handle more than one SG element).
205f11c7f63SJim Harris    // Since most run time UNMAP requests use 1K or less buffer space,
206f11c7f63SJim Harris    // there is no performance degradation with only supporting a
207f11c7f63SJim Harris    // single physical page.  For best results allocate the maximum
208f11c7f63SJim Harris    // amount of memory the device can handle up to the maximum of 4K.
209f11c7f63SJim Harris    return MIN(SATI_DSM_MAX_BUFFER_SIZE/sequence->device->logical_block_size,
210f11c7f63SJim Harris               sequence->device->max_lba_range_entry_blocks);
211f11c7f63SJim Harris }
212f11c7f63SJim Harris 
213f11c7f63SJim Harris /**
214f11c7f63SJim Harris  * @brief This method will be called before starting the first unmap translation
215f11c7f63SJim Harris  *
216f11c7f63SJim Harris  * @return Indicate if the translation was successful.
217f11c7f63SJim Harris  * @retval SATI_SUCCESS This is returned if the command translation was
218f11c7f63SJim Harris  *         successful and no further processing.
219f11c7f63SJim Harris  * @retval SATI_COMPLETE - The initial processing was completed successfully
220f11c7f63SJim Harris  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA - Failed the initial processing
221f11c7f63SJim Harris  */
sati_unmap_initial_processing(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)222f11c7f63SJim Harris SATI_STATUS sati_unmap_initial_processing(
223f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
224f11c7f63SJim Harris    void                       * scsi_io,
225f11c7f63SJim Harris    void                       * ata_io
226f11c7f63SJim Harris )
227f11c7f63SJim Harris {
228f11c7f63SJim Harris    SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
229f11c7f63SJim Harris    U8 * cdb;
230f11c7f63SJim Harris    U16 unmap_length;
231f11c7f63SJim Harris    U32 descriptor_length;
232f11c7f63SJim Harris    U32 index;
233f11c7f63SJim Harris    U32 max_dsm_blocks;
234f11c7f63SJim Harris    U8  unmap_param_list[8];
235f11c7f63SJim Harris 
236f11c7f63SJim Harris    unmap_process_state = &sequence->command_specific_data.unmap_process_state;
237f11c7f63SJim Harris 
238f11c7f63SJim Harris    // Set up the sequence type for unmap translation
239f11c7f63SJim Harris    sequence->type = SATI_SEQUENCE_UNMAP;
240f11c7f63SJim Harris 
241f11c7f63SJim Harris    // Make sure the device is TRIM capable
242f11c7f63SJim Harris    if ((sequence->device->capabilities & SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
243f11c7f63SJim Harris        != SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
244f11c7f63SJim Harris    {
245f11c7f63SJim Harris       // Can't send TRIM request to device that does not support it
246f11c7f63SJim Harris       sati_scsi_sense_data_construct(
247f11c7f63SJim Harris          sequence,
248f11c7f63SJim Harris          scsi_io,
249f11c7f63SJim Harris          SCSI_STATUS_CHECK_CONDITION,
250f11c7f63SJim Harris          SCSI_SENSE_ILLEGAL_REQUEST,
251f11c7f63SJim Harris          SCSI_ASC_INVALID_FIELD_IN_CDB,
252f11c7f63SJim Harris          SCSI_ASCQ_INVALID_FIELD_IN_CDB
253f11c7f63SJim Harris       );
254f11c7f63SJim Harris       return SATI_FAILURE_CHECK_RESPONSE_DATA;
255f11c7f63SJim Harris    }
256f11c7f63SJim Harris 
257f11c7f63SJim Harris    // get the amount of data being sent from the cdb
258f11c7f63SJim Harris    cdb = sati_cb_get_cdb_address(scsi_io);
259f11c7f63SJim Harris    unmap_length = (sati_get_cdb_byte(cdb, 7) << 8) | sati_get_cdb_byte(cdb, 8);
260f11c7f63SJim Harris 
261f11c7f63SJim Harris    // If nothing has been requested return success now.
262f11c7f63SJim Harris    if (unmap_length == 0)
263f11c7f63SJim Harris    {
264f11c7f63SJim Harris        // SAT: This is not an error
265f11c7f63SJim Harris        return SATI_SUCCESS;
266f11c7f63SJim Harris    }
267f11c7f63SJim Harris    if (unmap_length < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST)
268f11c7f63SJim Harris    {
269f11c7f63SJim Harris       // Not enough length specified in the CDB
270f11c7f63SJim Harris       sati_scsi_sense_data_construct(
271f11c7f63SJim Harris          sequence,
272f11c7f63SJim Harris          scsi_io,
273f11c7f63SJim Harris          SCSI_STATUS_CHECK_CONDITION,
274f11c7f63SJim Harris          SCSI_SENSE_ILLEGAL_REQUEST,
275f11c7f63SJim Harris          SCSI_ASC_INVALID_FIELD_IN_CDB,
276f11c7f63SJim Harris          SCSI_ASCQ_INVALID_FIELD_IN_CDB
277f11c7f63SJim Harris       );
278f11c7f63SJim Harris       return SATI_FAILURE_CHECK_RESPONSE_DATA;
279f11c7f63SJim Harris    }
280f11c7f63SJim Harris 
281f11c7f63SJim Harris    sequence->allocation_length = unmap_length;
282f11c7f63SJim Harris 
283f11c7f63SJim Harris    // Get the unmap parameter header
284f11c7f63SJim Harris    for(index = 0; index < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST; index++)
285f11c7f63SJim Harris    {
286f11c7f63SJim Harris       sati_get_data_byte(sequence, scsi_io, index,   &unmap_param_list[index]);
287f11c7f63SJim Harris    }
288f11c7f63SJim Harris    descriptor_length = (unmap_param_list[2] << 8) | unmap_param_list[3];
289f11c7f63SJim Harris 
290f11c7f63SJim Harris    // Check length again
291f11c7f63SJim Harris    if (descriptor_length == 0)
292f11c7f63SJim Harris    {
293f11c7f63SJim Harris        // SAT: This is not an error
294f11c7f63SJim Harris        return SATI_SUCCESS;
295f11c7f63SJim Harris    }
296f11c7f63SJim Harris 
297f11c7f63SJim Harris    if ((U32)(unmap_length - SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST) < descriptor_length)
298f11c7f63SJim Harris    {
299f11c7f63SJim Harris       // Not enough length specified in the CDB
300f11c7f63SJim Harris       sati_scsi_sense_data_construct(
301f11c7f63SJim Harris          sequence,
302f11c7f63SJim Harris          scsi_io,
303f11c7f63SJim Harris          SCSI_STATUS_CHECK_CONDITION,
304f11c7f63SJim Harris          SCSI_SENSE_ILLEGAL_REQUEST,
305f11c7f63SJim Harris          SCSI_ASC_INVALID_FIELD_IN_CDB,
306f11c7f63SJim Harris          SCSI_ASCQ_INVALID_FIELD_IN_CDB
307f11c7f63SJim Harris       );
308f11c7f63SJim Harris       return SATI_FAILURE_CHECK_RESPONSE_DATA;
309f11c7f63SJim Harris    }
310f11c7f63SJim Harris 
311f11c7f63SJim Harris    // Save the maximum unmap block descriptors in this request
312f11c7f63SJim Harris    unmap_process_state->max_unmap_block_descriptors =
313f11c7f63SJim Harris        descriptor_length/SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
314f11c7f63SJim Harris 
315f11c7f63SJim Harris    // Determine the maximum size of the write buffer that will be required
316f11c7f63SJim Harris    // for the translation in terms of number of blocks
317f11c7f63SJim Harris    max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);
318f11c7f63SJim Harris 
319f11c7f63SJim Harris    // Save the maximum number of DSM descriptors we can send during the translation
320f11c7f63SJim Harris    unmap_process_state->max_lba_range_entries =
321f11c7f63SJim Harris        (max_dsm_blocks*sequence->device->logical_block_size)/sizeof(TRIM_PAIR);
322f11c7f63SJim Harris 
323f11c7f63SJim Harris    // Get the write buffer for the translation
324f11c7f63SJim Harris    sati_cb_allocate_dma_buffer(
325f11c7f63SJim Harris       scsi_io,
326f11c7f63SJim Harris       max_dsm_blocks*sequence->device->logical_block_size,
327f11c7f63SJim Harris       &(unmap_process_state->virtual_unmap_buffer),
328f11c7f63SJim Harris       &(unmap_process_state->physical_unmap_buffer_low),
329f11c7f63SJim Harris       &(unmap_process_state->physical_unmap_buffer_high));
330f11c7f63SJim Harris 
331f11c7f63SJim Harris    // Makes sure we have a buffer
332f11c7f63SJim Harris    if (unmap_process_state->virtual_unmap_buffer == NULL)
333f11c7f63SJim Harris    {
334f11c7f63SJim Harris       // Resource failure
335f11c7f63SJim Harris       sati_scsi_sense_data_construct(
336f11c7f63SJim Harris          sequence,
337f11c7f63SJim Harris          scsi_io,
3383e0a9f1fSJim Harris          SCSI_STATUS_BUSY,
3393e0a9f1fSJim Harris          SCSI_SENSE_NO_SENSE,
340f11c7f63SJim Harris          SCSI_ASC_NO_ADDITIONAL_SENSE,
341f11c7f63SJim Harris          SCSI_ASCQ_NO_ADDITIONAL_SENSE
342f11c7f63SJim Harris       );
343f11c7f63SJim Harris       return SATI_FAILURE_CHECK_RESPONSE_DATA;
344f11c7f63SJim Harris    }
345f11c7f63SJim Harris 
346f11c7f63SJim Harris    // Get the first SGL entry.  This code will only use one 4K page so will
347f11c7f63SJim Harris    // only utilize the first sge.
348f11c7f63SJim Harris    sati_cb_sgl_next_sge(scsi_io,
349f11c7f63SJim Harris                         ata_io,
350f11c7f63SJim Harris                         NULL,
351f11c7f63SJim Harris                         &(unmap_process_state->unmap_buffer_sgl_pair));
352f11c7f63SJim Harris 
353f11c7f63SJim Harris    // Load the first descriptor to start the translation loop
354f11c7f63SJim Harris    unmap_process_state->current_unmap_block_descriptor_index =
355f11c7f63SJim Harris       SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST;
356f11c7f63SJim Harris    sati_unmap_load_next_descriptor(sequence,scsi_io);
357f11c7f63SJim Harris 
358f11c7f63SJim Harris    // Next state will be incomplete since translation
359f11c7f63SJim Harris    // will require a callback and possibly more requests.
360f11c7f63SJim Harris    sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
361f11c7f63SJim Harris 
362f11c7f63SJim Harris    return SATI_COMPLETE;
363f11c7f63SJim Harris }
364f11c7f63SJim Harris 
365f11c7f63SJim Harris /**
366f11c7f63SJim Harris  * @brief This method will process each unmap sequence.
367f11c7f63SJim Harris  *
368f11c7f63SJim Harris  * @return Indicate if the translation was successful.
369f11c7f63SJim Harris  * @retval SATI_SUCCESS
370f11c7f63SJim Harris  */
sati_unmap_process(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)371f11c7f63SJim Harris SATI_STATUS sati_unmap_process(
372f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
373f11c7f63SJim Harris    void                       * scsi_io,
374f11c7f63SJim Harris    void                       * ata_io
375f11c7f63SJim Harris )
376f11c7f63SJim Harris {
377f11c7f63SJim Harris    SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
378f11c7f63SJim Harris    SATI_LBA dsm_descriptor_lba_count;
379f11c7f63SJim Harris    U32 dsm_descriptor;
380f11c7f63SJim Harris    U32 dsm_bytes;
381f11c7f63SJim Harris    U32 dsm_remainder_bytes;
382f11c7f63SJim Harris    U32 dsm_blocks;
383f11c7f63SJim Harris    U32 max_dsm_blocks;
384f11c7f63SJim Harris 
385f11c7f63SJim Harris    unmap_process_state = &sequence->command_specific_data.unmap_process_state;
386f11c7f63SJim Harris 
387f11c7f63SJim Harris    // Set up the starting address of the buffer for this portion of the translation
388f11c7f63SJim Harris    unmap_process_state->current_dsm_descriptor = unmap_process_state->virtual_unmap_buffer;
389f11c7f63SJim Harris    dsm_descriptor = 0;
390f11c7f63SJim Harris 
391f11c7f63SJim Harris    // Translate as much as we can
392f11c7f63SJim Harris    while ((dsm_descriptor < unmap_process_state->max_lba_range_entries) &&
393f11c7f63SJim Harris           (unmap_process_state->current_lba_count > 0)) {
394f11c7f63SJim Harris       // See if the LBA count will fit in to a single descriptor
395f11c7f63SJim Harris       if (unmap_process_state->current_lba_count > SATI_DSM_MAX_SECTOR_COUNT) {
396f11c7f63SJim Harris          // Can't fit all of the lbas for this descriptor in to
397f11c7f63SJim Harris          // one DSM request.  Adjust the current LbaCount and total
398f11c7f63SJim Harris          // remaining for the next descriptor
399f11c7f63SJim Harris          dsm_descriptor_lba_count = SATI_DSM_MAX_SECTOR_COUNT;
400f11c7f63SJim Harris          unmap_process_state->current_lba_count -= SATI_DSM_MAX_SECTOR_COUNT;
401f11c7f63SJim Harris          unmap_process_state->next_lba =
402f11c7f63SJim Harris              unmap_process_state->current_lba + SATI_DSM_MAX_SECTOR_COUNT;
403f11c7f63SJim Harris       } else {
404f11c7f63SJim Harris          // It all fits in to one descriptor
405f11c7f63SJim Harris          dsm_descriptor_lba_count = unmap_process_state->current_lba_count;
406f11c7f63SJim Harris          unmap_process_state->current_lba_count = 0;
407f11c7f63SJim Harris       }
408f11c7f63SJim Harris 
409f11c7f63SJim Harris       // Fill in the ATA DSM descriptor
410f11c7f63SJim Harris       ((PTRIM_PAIR)(unmap_process_state->current_dsm_descriptor))->sector_address =
411f11c7f63SJim Harris           unmap_process_state->current_lba;
412f11c7f63SJim Harris       ((PTRIM_PAIR)(unmap_process_state->current_dsm_descriptor))->sector_count =
413f11c7f63SJim Harris           dsm_descriptor_lba_count;
414f11c7f63SJim Harris 
415f11c7f63SJim Harris       // See if we can move on to the next descriptor
416f11c7f63SJim Harris       if (unmap_process_state->current_lba_count == 0) {
417f11c7f63SJim Harris          // See if there is another descriptor
418f11c7f63SJim Harris          --unmap_process_state->max_unmap_block_descriptors;
419f11c7f63SJim Harris          if (unmap_process_state->max_unmap_block_descriptors > 0) {
420f11c7f63SJim Harris             // Move on to the next descriptor
421f11c7f63SJim Harris             sati_unmap_load_next_descriptor(sequence,scsi_io);
422f11c7f63SJim Harris          }
423f11c7f63SJim Harris       } else {
424f11c7f63SJim Harris          // Move to the next LBA in this descriptor
425f11c7f63SJim Harris          unmap_process_state->current_lba = unmap_process_state->next_lba;
426f11c7f63SJim Harris       }
427f11c7f63SJim Harris 
428f11c7f63SJim Harris       // Make sure the LBA does not exceed 48 bits...
429f11c7f63SJim Harris       ASSERT(unmap_process_state->current_lba <= SATI_DSM_MAX_SECTOR_ADDRESS);
430f11c7f63SJim Harris 
431f11c7f63SJim Harris       // Increment the number of descriptors used and point to the next entry
432f11c7f63SJim Harris       dsm_descriptor++;
433f11c7f63SJim Harris       unmap_process_state->current_dsm_descriptor =
434f11c7f63SJim Harris           (U8 *)(unmap_process_state->current_dsm_descriptor) + sizeof(TRIM_PAIR);
435f11c7f63SJim Harris    }
436f11c7f63SJim Harris 
437f11c7f63SJim Harris    // Calculate number of blocks we have filled in
438f11c7f63SJim Harris    dsm_blocks     = sati_unmap_calculate_dsm_blocks(sequence,dsm_descriptor);
439f11c7f63SJim Harris    dsm_bytes      = dsm_blocks * sequence->device->logical_block_size;
440f11c7f63SJim Harris    max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);
441f11c7f63SJim Harris 
442f11c7f63SJim Harris    // The current_dsm_descriptor points to the next location in the buffer
443f11c7f63SJim Harris    // Get the remaining bytes from the last translated descriptor
444f11c7f63SJim Harris    // to the end of the 4k buffer.
445f11c7f63SJim Harris    dsm_remainder_bytes = sequence->device->logical_block_size;
446f11c7f63SJim Harris    dsm_remainder_bytes -= (U32)((POINTER_UINT)unmap_process_state->current_dsm_descriptor &
447f11c7f63SJim Harris                                 (sequence->device->logical_block_size-1));
448f11c7f63SJim Harris 
449f11c7f63SJim Harris    // If there was no remainder, the complete buffer was filled in.
450f11c7f63SJim Harris    if (dsm_remainder_bytes != sequence->device->logical_block_size)
451f11c7f63SJim Harris    {
452f11c7f63SJim Harris        // Add on the remaining unfilled blocks
453f11c7f63SJim Harris        dsm_remainder_bytes += (sequence->device->logical_block_size * (max_dsm_blocks - dsm_blocks));
454f11c7f63SJim Harris 
455f11c7f63SJim Harris        // According to ATA-8, if the DSM buffer is not completely filled with
456f11c7f63SJim Harris        // valid DSM descriptor data, the remaining portion of the
457f11c7f63SJim Harris        // buffer must be filled in with zeros.
458f11c7f63SJim Harris        memset((U8 *)unmap_process_state->current_dsm_descriptor, 0, dsm_remainder_bytes);
459f11c7f63SJim Harris    }
460f11c7f63SJim Harris 
461f11c7f63SJim Harris    // Tell scic to utilize this sgl pair for write DMA processing of
462f11c7f63SJim Harris    // the SCSI UNMAP translation with the total number of bytes for this transfer
463f11c7f63SJim Harris    sati_cb_sge_write(unmap_process_state->unmap_buffer_sgl_pair,
464f11c7f63SJim Harris                      unmap_process_state->physical_unmap_buffer_low,
465f11c7f63SJim Harris                      unmap_process_state->physical_unmap_buffer_high,
466f11c7f63SJim Harris                      dsm_bytes);
467f11c7f63SJim Harris 
468f11c7f63SJim Harris    // Construct the unmap ATA request
469f11c7f63SJim Harris    sati_unmap_construct(sequence,
470f11c7f63SJim Harris                         scsi_io,
471f11c7f63SJim Harris                         ata_io,
472f11c7f63SJim Harris                         dsm_blocks);
473f11c7f63SJim Harris 
474f11c7f63SJim Harris    // Determine sequence next state based on whether there is more translation
475f11c7f63SJim Harris    // to complete
476f11c7f63SJim Harris    if (unmap_process_state->current_lba_count == 0)
477f11c7f63SJim Harris    {
478f11c7f63SJim Harris        // used for completion routine to determine if there is more processing
479f11c7f63SJim Harris        sequence->state = SATI_SEQUENCE_STATE_FINAL;
480f11c7f63SJim Harris    }
481f11c7f63SJim Harris    // This requests has already translated the SGL, have SCIC skip SGL translataion
482f11c7f63SJim Harris    return SATI_SUCCESS_SGL_TRANSLATED;
483f11c7f63SJim Harris }
484f11c7f63SJim Harris 
485f11c7f63SJim Harris //******************************************************************************
486f11c7f63SJim Harris //* P U B L I C   M E T H O D S
487f11c7f63SJim Harris //******************************************************************************
488f11c7f63SJim Harris 
489f11c7f63SJim Harris /**
490f11c7f63SJim Harris  * @brief This method will handle termination of the
491f11c7f63SJim Harris  *        SCSI unmap translation and frees previously allocated
492f11c7f63SJim Harris  *        dma buffer.
493f11c7f63SJim Harris  *
494f11c7f63SJim Harris  * @return None
495f11c7f63SJim Harris  */
sati_unmap_terminate(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)496f11c7f63SJim Harris void sati_unmap_terminate(
497f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
498f11c7f63SJim Harris    void                       * scsi_io,
499f11c7f63SJim Harris    void                       * ata_io
500f11c7f63SJim Harris )
501f11c7f63SJim Harris {
502f11c7f63SJim Harris    SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
503f11c7f63SJim Harris    unmap_process_state = &sequence->command_specific_data.unmap_process_state;
504f11c7f63SJim Harris 
505f11c7f63SJim Harris    if (unmap_process_state->virtual_unmap_buffer != NULL)
506f11c7f63SJim Harris    {
507f11c7f63SJim Harris       sati_cb_free_dma_buffer(scsi_io, unmap_process_state->virtual_unmap_buffer);
508f11c7f63SJim Harris       unmap_process_state->virtual_unmap_buffer = NULL;
509f11c7f63SJim Harris    }
510f11c7f63SJim Harris }
511f11c7f63SJim Harris 
512f11c7f63SJim Harris /**
513f11c7f63SJim Harris  * @brief This method will translate the SCSI Unmap command
514f11c7f63SJim Harris  *        into corresponding ATA commands.  Depending upon the capabilities
515f11c7f63SJim Harris  *        supported by the target different ATA commands can be selected.
516f11c7f63SJim Harris  *        Additionally, in some cases more than a single ATA command may
517f11c7f63SJim Harris  *        be required.
518f11c7f63SJim Harris  *
519f11c7f63SJim Harris  * @return Indicate if the command translation succeeded.
520f11c7f63SJim Harris  * @retval SATI_SUCCESS This is returned if the command translation was
521f11c7f63SJim Harris  *         successful.
522f11c7f63SJim Harris  * @retval SATI_COMPLETE This is returned if the command translation was
523f11c7f63SJim Harris  *         successful and no ATA commands need to be set.
524f11c7f63SJim Harris  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
525f11c7f63SJim Harris  *         sense data has been created as a result of something specified
526f11c7f63SJim Harris  *         in the parameter data fields.
527f11c7f63SJim Harris  */
sati_unmap_translate_command(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)528f11c7f63SJim Harris SATI_STATUS sati_unmap_translate_command(
529f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
530f11c7f63SJim Harris    void                       * scsi_io,
531f11c7f63SJim Harris    void                       * ata_io
532f11c7f63SJim Harris )
533f11c7f63SJim Harris {
534f11c7f63SJim Harris    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
535f11c7f63SJim Harris    SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
536f11c7f63SJim Harris 
537f11c7f63SJim Harris    unmap_process_state = &sequence->command_specific_data.unmap_process_state;
538f11c7f63SJim Harris 
539f11c7f63SJim Harris    // Determine if this is the first step in the unmap sequence
540f11c7f63SJim Harris    if ( sequence->state == SATI_SEQUENCE_STATE_INITIAL )
541f11c7f63SJim Harris    {
542f11c7f63SJim Harris        status = sati_unmap_initial_processing(sequence,scsi_io,ata_io);
543f11c7f63SJim Harris        if (status != SATI_COMPLETE)
544f11c7f63SJim Harris        {
545f11c7f63SJim Harris           return status;
546f11c7f63SJim Harris        }
547f11c7f63SJim Harris    }
548f11c7f63SJim Harris    // Translate the next portion of the UNMAP request
549f11c7f63SJim Harris    return sati_unmap_process(sequence, scsi_io, ata_io);
550f11c7f63SJim Harris }
551f11c7f63SJim Harris 
552f11c7f63SJim Harris /**
553f11c7f63SJim Harris  * @brief This method will translate the ATA command register FIS
554f11c7f63SJim Harris  *        response into an appropriate SCSI response for Unmap.
555f11c7f63SJim Harris  *        For more information on the parameters passed to this method,
556f11c7f63SJim Harris  *        please reference sati_translate_response().
557f11c7f63SJim Harris  *
558f11c7f63SJim Harris  * @return Indicate if the response translation succeeded.
559f11c7f63SJim Harris  * @retval SATI_SUCCESS This is returned if the command translation was
560f11c7f63SJim Harris  *         successful.
561f11c7f63SJim Harris  * @retval SATI_COMPLETE This is returned if the command translation was
562f11c7f63SJim Harris  *         successful and no ATA commands need to be set.
563f11c7f63SJim Harris  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
564f11c7f63SJim Harris  *         sense data has been created as a result of something specified
565f11c7f63SJim Harris  *         in the parameter data fields.
566f11c7f63SJim Harris  */
sati_unmap_translate_response(SATI_TRANSLATOR_SEQUENCE_T * sequence,void * scsi_io,void * ata_io)567f11c7f63SJim Harris SATI_STATUS sati_unmap_translate_response(
568f11c7f63SJim Harris    SATI_TRANSLATOR_SEQUENCE_T * sequence,
569f11c7f63SJim Harris    void                       * scsi_io,
570f11c7f63SJim Harris    void                       * ata_io
571f11c7f63SJim Harris )
572f11c7f63SJim Harris {
573f11c7f63SJim Harris    U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
574f11c7f63SJim Harris    SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
575f11c7f63SJim Harris    SATI_STATUS sati_status = SATI_COMPLETE;
576f11c7f63SJim Harris 
577f11c7f63SJim Harris    unmap_process_state = &sequence->command_specific_data.unmap_process_state;
578f11c7f63SJim Harris 
579f11c7f63SJim Harris    if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
580f11c7f63SJim Harris    {
581f11c7f63SJim Harris       sequence->state = SATI_SEQUENCE_STATE_FINAL;
582f11c7f63SJim Harris       sati_scsi_sense_data_construct(
583f11c7f63SJim Harris          sequence,
584f11c7f63SJim Harris          scsi_io,
585f11c7f63SJim Harris          SCSI_STATUS_CHECK_CONDITION,
586f11c7f63SJim Harris          SCSI_SENSE_ABORTED_COMMAND,
587f11c7f63SJim Harris          SCSI_ASC_NO_ADDITIONAL_SENSE,
588f11c7f63SJim Harris          SCSI_ASCQ_NO_ADDITIONAL_SENSE
589f11c7f63SJim Harris       );
590f11c7f63SJim Harris       // All done, terminate the translation
591f11c7f63SJim Harris       sati_unmap_terminate(sequence, scsi_io, ata_io);
592f11c7f63SJim Harris    }
593f11c7f63SJim Harris    else
594f11c7f63SJim Harris    {
595f11c7f63SJim Harris       if (sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE)
596f11c7f63SJim Harris       {
597f11c7f63SJim Harris           // All done, terminate the translation
598f11c7f63SJim Harris           sati_unmap_terminate(sequence, scsi_io, ata_io);
599f11c7f63SJim Harris       }
600f11c7f63SJim Harris       else
601f11c7f63SJim Harris       {
602f11c7f63SJim Harris           // Still translating
603f11c7f63SJim Harris           sati_status = SATI_SEQUENCE_STATE_INCOMPLETE;
604f11c7f63SJim Harris       }
605f11c7f63SJim Harris    }
606f11c7f63SJim Harris    return sati_status;
607f11c7f63SJim Harris }
608f11c7f63SJim Harris 
609f11c7f63SJim Harris #endif // !defined(DISABLE_SATI_UNMAP)
610