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