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