xref: /freebsd/sys/dev/isci/scil/sati_reassign_blocks.c (revision 63a938566d524836885917d95bd491aa4400b181)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3  *
4  * This file is provided under a dual BSD/GPLv2 license.  When using or
5  * redistributing this file, you may do so under either license.
6  *
7  * GPL LICENSE SUMMARY
8  *
9  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of version 2 of the GNU General Public License as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23  * The full GNU General Public License is included in this distribution
24  * in the file called LICENSE.GPL.
25  *
26  * BSD LICENSE
27  *
28  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  *
35  *   * Redistributions of source code must retain the above copyright
36  *     notice, this list of conditions and the following disclaimer.
37  *   * Redistributions in binary form must reproduce the above copyright
38  *     notice, this list of conditions and the following disclaimer in
39  *     the documentation and/or other materials provided with the
40  *     distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57 
58 /**
59  * @file
60  * @brief This file contains the method implementations required to
61  *        translate the SCSI reassign blocks command.
62  */
63 
64 #if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
65 
66 #include <dev/isci/scil/sati_reassign_blocks.h>
67 #include <dev/isci/scil/sati_callbacks.h>
68 #include <dev/isci/scil/sati_move.h>
69 #include <dev/isci/scil/sati_write.h>
70 #include <dev/isci/scil/sati_translator_sequence.h>
71 #include <dev/isci/scil/sati_util.h>
72 #include <dev/isci/scil/intel_scsi.h>
73 
74 
75 //******************************************************************************
76 //* P R I V A T E   M E T H O D S
77 //******************************************************************************
78 // static SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T reassign_blocks_processing_state;
79 
80 /**
81  * @brief This method copies short 24bits LBA bytes to the command register
82  * @return Indicate if the method was successfully completed.
83  * @retval SATI_SUCCESS This is returned in all other cases.
84  */
85 static
86 void set_current_lba(U8 * lba, void  * ata_io)
87 {
88    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
89 
90    sati_set_ata_lba_low(register_fis, lba[0]);
91    sati_set_ata_lba_mid(register_fis, lba[1]);
92    sati_set_ata_lba_high(register_fis, lba[2]);
93    sati_set_ata_device_head(register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE | (lba[3] & 0x0F));
94 
95 
96 }
97 
98 /**
99  * @brief This method copies short 48bits LBA bytes to the command register
100  * @return Indicate if the method was successfully completed.
101  * @retval SATI_SUCCESS This is returned in all other cases.
102  */
103 static
104 void set_current_long_lba(U8 * lba, void  * ata_io)
105 {
106    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
107 
108    sati_set_ata_lba_low(register_fis, lba[0]);
109    sati_set_ata_lba_mid(register_fis, lba[1]);
110    sati_set_ata_lba_high(register_fis, lba[2]);
111    sati_set_ata_lba_low_exp(register_fis, lba[3]);
112    sati_set_ata_lba_mid_exp(register_fis, lba[4]);
113    sati_set_ata_lba_high_exp(register_fis, lba[5]);
114 }
115 
116 /**
117  * @brief This method performs the SCSI VERIFY command translation
118  *        functionality.
119  *        This includes:
120  *        - setting the command register
121  *        - setting the device head register
122  *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
123  *        For more information on the parameters passed to this method,
124  *        please reference sati_translate_command().
125  *
126  * @return Indicate if the method was successfully completed.
127  * @retval SATI_SUCCESS This is returned in all other cases.
128  */
129 static
130 SATI_STATUS sati_reassign_blocks_verify_command(
131    SATI_TRANSLATOR_SEQUENCE_T * sequence,
132    void                       * scsi_io,
133    void                       * ata_io
134 )
135 {
136    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
137 
138    sati_ata_non_data_command(ata_io, sequence);
139 
140    // Ensure the device supports the 48 bit feature set.
141    if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
142       sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS_EXT);
143    else
144       sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS);
145 
146    return SATI_SUCCESS;
147 }
148 
149 /**
150  * @brief This method performs the SCSI Write sector command translation
151  *        functionality.
152  *        This includes:
153  *        - setting the command register
154  *        - setting the device head register
155  *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
156  *        For more information on the parameters passed to this method,
157  *        please reference sati_translate_command().
158  *
159  * @return Indicate if the method was successfully completed.
160  * @retval SATI_SUCCESS This is returned in all other cases.
161  */
162 static
163 SATI_STATUS sati_reassign_blocks_write_command(
164    SATI_TRANSLATOR_SEQUENCE_T * sequence,
165    void                       * scsi_io,
166    void                       * ata_io
167 )
168 {
169    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
170 
171    sati_ata_non_data_command(ata_io, sequence);
172    sequence->data_direction = SATI_DATA_DIRECTION_OUT;
173 
174 //   sati_set_ata_sector_count(register_fis, 1);
175 //   status=sati_move_set_sector_count(sequence,scsi_io,ata_io,1,0);
176 
177    // Ensure the device supports the 48 bit feature set.
178    if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
179       sati_set_ata_command(register_fis, ATA_WRITE_DMA_EXT);
180    else
181       sati_set_ata_command(register_fis, ATA_WRITE_DMA);
182 
183    return SATI_SUCCESS; //sati_move_set_sector_count(sequence,scsi_io,ata_io,1,0);
184 }
185 
186 /**
187  * @brief This method performs the retrieving of parameter LBA praparation and setting
188  *        processing flags before/after calling SCSI Verify sector command.
189  * @return Indicate if the method was successfully completed.
190  * @retval SATI_SUCCESS This is returned in all other cases.
191  */
192 static
193 SATI_STATUS sati_reassign_blocks_verify_condition(
194    SATI_TRANSLATOR_SEQUENCE_T * sequence,
195    void     * scsi_io,
196    void     * ata_io
197 )
198 {
199    U8 current_lba_bytes[8] = {0,0,0,0,0,0,0,0};
200    U32 lba_offset;
201    U8 page_size;
202    U32 index;
203    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
204 
205    lba_offset = sequence->command_specific_data.reassign_blocks_process_state.lba_offset;
206    page_size = sequence->command_specific_data.reassign_blocks_process_state.lba_size;
207 
208    for(index = 0; index < page_size; index++)
209    {
210       sati_get_data_byte(sequence, scsi_io, lba_offset+index,   &current_lba_bytes[index]);
211    }
212 
213    if (page_size == 4)
214       set_current_lba(current_lba_bytes, ata_io);
215    else
216       set_current_long_lba(current_lba_bytes, ata_io);
217 
218    status = sati_reassign_blocks_verify_command(sequence, scsi_io, ata_io);
219    sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba++;
220    sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_READY_TO_SEND;
221    return  status;
222 }
223 
224 /**
225  * @brief This method performs the retrieving of parameter LBA praparation and setting
226  *        processing flags before/after calling SCSI Write sector command.
227  * @return Indicate if the method was successfully completed.
228  * @retval SATI_SUCCESS This is returned in all other cases.
229  */
230 static
231 SATI_STATUS sati_reassign_blocks_write_condition(
232    SATI_TRANSLATOR_SEQUENCE_T * sequence,
233    void     * scsi_io,
234    void     * ata_io
235 )
236 {
237    U8 current_lba_bytes[8] = {0,0,0,0,0,0,0,0};
238    U32 lba_offset;
239    U8 page_size;
240    U32 index;
241    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
242 
243    lba_offset = sequence->command_specific_data.reassign_blocks_process_state.lba_offset;
244    page_size = sequence->command_specific_data.reassign_blocks_process_state.lba_size;
245 
246    for(index = 0; index < page_size; index++)
247    {
248       sati_get_data_byte(sequence, scsi_io, lba_offset+index,   &current_lba_bytes[index]);
249    }
250 
251    if (page_size == 4)
252       set_current_lba(current_lba_bytes, ata_io);
253    else
254       set_current_long_lba(current_lba_bytes, ata_io);
255 
256    status = sati_reassign_blocks_write_command(sequence, scsi_io, ata_io);
257    sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba++;
258    sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_READY_TO_SEND;
259    return  status ;
260 }
261 
262 
263 /**
264  * @brief This method will perform the pre-processing of Reassign Blocks command and parameter.
265  */
266 static
267 void  sati_reassign_blocks_initial_processing(
268    SATI_TRANSLATOR_SEQUENCE_T * sequence,
269    void                       * scsi_io,
270    void                       * ata_io
271 )
272 {
273    U32 index;
274    U8 long_lba_bit;
275    U8 long_list_bit;
276    U8 lba_offset;
277    U8  page_size;
278    U32 data_transfer_length;
279    U8 header_bytes[4]={0,0,0,0};
280 
281    U8 * cdb = sati_cb_get_cdb_address(scsi_io);
282 
283    //A long LBA (LONGLBA) bit set to zero specifies that the REASSIGN BLOCKS defective LBA list contains four-byte LBAs.
284    //A LONGLBA bit set to one specifies that the REASSIGN BLOCKS defective LBA list contains eight-byte LBAs.
285    if ((sati_get_cdb_byte(cdb, 1) & SCSI_REASSIGN_BLOCKS_LONGLBA_BIT) == 0)
286    {
287       long_lba_bit=0;
288       page_size = 4; //beginning of lba list
289    }
290    else
291    {
292       long_lba_bit=1;
293       page_size = 8;
294    }
295 
296    //The long list (LONGLIST) bit specifies which parameter list header
297    if ((sati_get_cdb_byte(cdb, 1) & SCSI_REASSIGN_BLOCKS_LONGLIST_BIT) == 0)
298    {
299       long_list_bit=0;
300    }
301    else
302    {
303       long_list_bit=1;
304    }
305 
306    sequence->allocation_length = 4; //Pre-set allocation_length so that the header can be retrieved
307 
308    //Get 4 bytes for headers (byte 2 & byte 3 for short header; long header all 4 bytes)
309    for(index = 0; index < 4; index++)
310    {
311       sati_get_data_byte(sequence, scsi_io, index,   &header_bytes[index]);
312    }
313 
314    lba_offset = 4; //beginning of lba list
315 
316    if (long_list_bit==0)
317    {
318       //Header byte 2 and 3 is the parameter list length
319       data_transfer_length = (header_bytes[2]<<8) + header_bytes[3] + lba_offset;
320    }
321    else
322    {
323       //Header byte 0, 1, 2 and 3 contain the parameter list length
324       data_transfer_length = (header_bytes[0]<<24) + (header_bytes[1]<<16) +
325          (header_bytes[2]<<8) + header_bytes[3] + lba_offset;
326    }
327 
328    sequence->allocation_length = data_transfer_length;
329 
330    //Initialized the global processing state
331    sequence->command_specific_data.reassign_blocks_process_state.lba_size   =     page_size;
332    sequence->command_specific_data.reassign_blocks_process_state.lba_offset =     lba_offset;
333    sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba = 0;
334    sequence->command_specific_data.reassign_blocks_process_state.block_lists_size       = data_transfer_length  -  lba_offset;
335    sequence->command_specific_data.reassign_blocks_process_state.size_of_data_processed = 0;
336    sequence->command_specific_data.reassign_blocks_process_state.current_lba_processed  = FALSE;
337    sequence->command_specific_data.reassign_blocks_process_state.ata_command_status     = SATI_REASSIGN_BLOCKS_COMMAND_FAIL;
338 }
339 
340 /**
341  * @brief This method will get the data size of not yet processed data.
342  *
343  * @param[in] lba_process_state This parameter points to the processing state fields
344  *            of current block lba.
345  *
346  * @return This method returns the sizeof not yet processed data.
347  */
348 static
349 U32 sati_reassign_blocks_unprocessed_data_size(
350    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * lba_process_state
351 )
352 {
353    U32 unprocessed_data_size;
354 
355    if(lba_process_state->block_lists_size >= lba_process_state->size_of_data_processed)
356    {
357       unprocessed_data_size = lba_process_state->block_lists_size -
358          lba_process_state->size_of_data_processed;
359    }
360    else
361    {
362       unprocessed_data_size = 0;
363    }
364 
365    return unprocessed_data_size;
366 }
367 
368 
369 /**
370  * @brief This method will check verify the sector and issue multiple ATA set feature commands to complete the translation.
371  *
372  * @param[in] reassign_blocks_process_state This parameter points to the processing state fields
373  *            of current lba block.
374  *
375  *
376  * @return Indicate if the translation was successful.
377  * @retval SATI_SUCCESS
378  * @retval SATI_COMPLETE
379  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
380  */
381 static
382 SATI_STATUS sati_reassign_blocks_process_each_lba(
383    SATI_TRANSLATOR_SEQUENCE_T * sequence,
384    void                       * scsi_io,
385    void                       * ata_io
386    )
387 {
388    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
389    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
390 
391    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
392 
393    if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 0)&&
394       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_FAIL))
395    {
396       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
397       status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
398    }
399    else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 0)&&
400       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS))
401    {
402       // point to next lba
403       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
404       reassign_blocks_process_state->lba_offset += reassign_blocks_process_state->lba_size;
405       status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
406    }
407    else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 1)&&
408       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_FAIL))
409    {
410       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
411       status = sati_reassign_blocks_write_condition(sequence, scsi_io, ata_io);
412    }
413    else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 2) &&
414       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS))
415    {
416       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
417       status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
418    }
419    else //commands sent is 2; SATI_REASSIGN_BLOCKS_COMMAND_FAIL
420    {
421       status = SATI_FAILURE_CHECK_RESPONSE_DATA;
422    }
423 
424    return status;
425 }
426 
427 /**
428  * @brief This method will process the each lba.
429  *
430  * @param[in] reassign_blocks_process_state This parameter points to the processing state fields
431  *            of current lba.
432  *
433  * @return Indicate if the translation was successful.
434  * @retval SATI_SUCCESS
435  * @retval SATI_COMPLETE
436  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
437  */
438 static
439 SATI_STATUS sati_reassign_blocks_process(
440    SATI_TRANSLATOR_SEQUENCE_T * sequence,
441    void                       * scsi_io,
442    void                       * ata_io
443 )
444 {
445    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
446 
447    U32 page_size = 0; // in bytes
448    U32 size_of_data_to_be_processed;
449    U32 lba_offset;
450    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
451 
452    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
453 
454    lba_offset = reassign_blocks_process_state->lba_offset;
455    page_size  = reassign_blocks_process_state->lba_size;
456 
457 
458    if(sati_reassign_blocks_unprocessed_data_size(reassign_blocks_process_state) < page_size)
459    {
460       return status;
461    }
462 
463    // Any more lba blocks? If not, done.
464    if(reassign_blocks_process_state->block_lists_size ==
465       reassign_blocks_process_state->size_of_data_processed)
466    {
467       sequence->state = SATI_SEQUENCE_STATE_FINAL;
468       status = SATI_COMPLETE;
469    }
470    //start processing next lba
471    else
472    {
473       size_of_data_to_be_processed = reassign_blocks_process_state->block_lists_size
474          - reassign_blocks_process_state->size_of_data_processed;
475 
476       status = sati_reassign_blocks_process_each_lba(sequence, scsi_io, ata_io);
477 
478    }
479 
480    return status;
481 }
482 
483 //******************************************************************************
484 //* P U B L I C   M E T H O D S
485 //******************************************************************************
486 
487 /**
488  * @brief This method will translate the SCSI Reassign Blocks command
489  *        into corresponding ATA commands.  Depending upon the capabilities
490  *        supported by the target different ATA commands can be selected.
491  *        Additionally, in some cases more than a single ATA command may
492  *        be required.
493  *
494  * @return Indicate if the command translation succeeded.
495  * @retval SCI_SUCCESS This is returned if the command translation was
496  *         successful.
497  * @retval SCI_COMPLETE This is returned if the command translation was
498  *         successful and no ATA commands need to be set.
499  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
500  *         sense data has been created as a result of something specified
501  *         in the parameter data fields.
502  */
503 SATI_STATUS sati_reassign_blocks_translate_command(
504    SATI_TRANSLATOR_SEQUENCE_T * sequence,
505    void                       * scsi_io,
506    void                       * ata_io
507 )
508 {
509    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
510    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
511 
512    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
513 
514    sequence->type = SATI_SEQUENCE_REASSIGN_BLOCKS;
515 
516    //Initial processing if
517    if ( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
518    {
519       sati_reassign_blocks_initial_processing(
520          sequence,
521          scsi_io,
522          ata_io
523       );
524    }
525 
526    // start processing current lba
527    if(reassign_blocks_process_state->current_lba_processed)
528    {
529       reassign_blocks_process_state->ata_command_sent_for_current_lba = 0;
530       reassign_blocks_process_state->current_lba_processed = FALSE;
531    }
532 
533    status = sati_reassign_blocks_process(sequence, scsi_io, ata_io);
534 
535    if(reassign_blocks_process_state->block_lists_size ==
536       reassign_blocks_process_state->size_of_data_processed)
537    {
538       // Done this lba
539       sequence->state = SATI_SEQUENCE_STATE_FINAL;
540    }
541    else
542    {
543       sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
544    }
545 
546    if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
547    {
548       sequence->state = SATI_SEQUENCE_STATE_FINAL;
549       sati_scsi_sense_data_construct(
550          sequence,
551          scsi_io,
552          SCSI_STATUS_CHECK_CONDITION,
553          SCSI_SENSE_MEDIUM_ERROR,
554          SCSI_ASC_UNRECOVERED_READ_ERROR,
555          SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL
556       );
557    }
558 
559    return status;
560 }
561 
562 /**
563  * @brief This method will translate the ATA command register FIS
564  *        response into an appropriate SCSI response for Reassign Blocks
565  *        For more information on the parameters passed to this method,
566  *        please reference sati_translate_response().
567  *
568  * @return Indicate if the response translation succeeded.
569  * @retval SCI_SUCCESS This is returned if the data translation was
570  *         successful.
571  */
572 SATI_STATUS sati_reassign_blocks_translate_response(
573    SATI_TRANSLATOR_SEQUENCE_T * sequence,
574    void                       * scsi_io,
575    void                       * ata_io
576 )
577 {
578    U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
579    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
580 
581    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
582 
583    if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
584    {
585       reassign_blocks_process_state->ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_FAIL;
586 
587       //Checking for the number of ATA commands attempted on current LBA, stop
588       //the seaquence after 2 commands have returned errors.
589       if(reassign_blocks_process_state->ata_command_sent_for_current_lba < 2)
590       {
591          sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
592          reassign_blocks_process_state->size_of_data_processed -= reassign_blocks_process_state->lba_size;
593          return SATI_SEQUENCE_INCOMPLETE;
594       }
595       else
596       {
597          sati_scsi_sense_data_construct(
598             sequence,
599             scsi_io,
600             SCSI_STATUS_CHECK_CONDITION,
601             SCSI_SENSE_MEDIUM_ERROR,
602             SCSI_ASC_UNRECOVERED_READ_ERROR,
603             SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL
604          );
605       }
606 
607       return SATI_FAILURE_CHECK_RESPONSE_DATA;
608    }
609    else
610    {
611       reassign_blocks_process_state->ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS;
612       if (reassign_blocks_process_state->ata_command_sent_for_current_lba != 2)
613          reassign_blocks_process_state->current_lba_processed = TRUE;
614 
615       if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
616       {
617          return SATI_SEQUENCE_INCOMPLETE;
618       }
619    }
620    return SATI_COMPLETE;
621 }
622 
623 #endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
624 
625